@@ -13,58 +13,25 @@ import Version
13
13
14
14
/// Manages searching the MAS catalog through the iTunes Search and Lookup APIs.
15
15
class MasStoreSearch : StoreSearch {
16
- private let networkManager : NetworkManager
17
16
private static let appVersionExpression = Regex ( #"\"versionDisplay\"\:\"([^\"]+)\""# )
18
17
19
- enum Entity : String {
20
- case macSoftware
21
- case iPadSoftware
22
- case iPhoneSoftware = " software "
23
- }
18
+ // CommerceKit and StoreFoundation don't seem to expose the region of the Apple ID signed
19
+ // into the App Store. Instead, we'll make an educated guess that it matches the currently
20
+ // selected locale in macOS. This obviously isn't always going to match, but it's probably
21
+ // better than passing no "country" at all to the iTunes Search API.
22
+ // https://affiliate.itunes.apple.com/resources/documentation/itunes-store-web-service-search-api/
23
+ private let country : String ?
24
+ private let networkManager : NetworkManager
24
25
25
26
/// Designated initializer.
26
- init ( networkManager: NetworkManager = NetworkManager ( ) ) {
27
+ init (
28
+ country: String ? = Locale . autoupdatingCurrent. regionCode,
29
+ networkManager: NetworkManager = NetworkManager ( )
30
+ ) {
31
+ self . country = country
27
32
self . networkManager = networkManager
28
33
}
29
34
30
- /// Builds the search URL for an app.
31
- ///
32
- /// - Parameter appName: MAS app identifier.
33
- /// - Returns: URL for the search service or nil if appName can't be encoded.
34
- static func searchURL( for appName: String , ofEntity entity: Entity = . macSoftware) -> URL {
35
- guard var components = URLComponents ( string: " https://itunes.apple.com/search " ) else {
36
- fatalError ( " URLComponents failed to parse URL. " )
37
- }
38
-
39
- components. queryItems = [
40
- URLQueryItem ( name: " media " , value: " software " ) ,
41
- URLQueryItem ( name: " entity " , value: entity. rawValue) ,
42
- URLQueryItem ( name: " term " , value: appName) ,
43
- ]
44
- guard let url = components. url else {
45
- fatalError ( " URLComponents failed to generate URL. " )
46
- }
47
-
48
- return url
49
- }
50
-
51
- /// Builds the lookup URL for an app.
52
- ///
53
- /// - Parameter appId: MAS app identifier.
54
- /// - Returns: URL for the lookup service or nil if appId can't be encoded.
55
- static func lookupURL( forApp appId: Int ) -> URL {
56
- guard var components = URLComponents ( string: " https://itunes.apple.com/lookup " ) else {
57
- fatalError ( " URLComponents failed to parse URL. " )
58
- }
59
-
60
- components. queryItems = [ URLQueryItem ( name: " id " , value: " \( appId) " ) ]
61
- guard let url = components. url else {
62
- fatalError ( " URLComponents failed to generate URL. " )
63
- }
64
-
65
- return url
66
- }
67
-
68
35
/// Searches for an app.
69
36
///
70
37
/// - Parameter appName: MAS ID of app
@@ -79,7 +46,9 @@ class MasStoreSearch: StoreSearch {
79
46
}
80
47
81
48
let results = entities. map { entity -> Promise < [ SearchResult ] > in
82
- let url = MasStoreSearch . searchURL ( for: appName, ofEntity: entity)
49
+ guard let url = searchURL ( for: appName, inCountry: country, ofEntity: entity) else {
50
+ fatalError ( " Failed to build URL for \( appName) " )
51
+ }
83
52
return loadSearchResults ( url)
84
53
}
85
54
@@ -96,7 +65,9 @@ class MasStoreSearch: StoreSearch {
96
65
/// - Returns: A Promise for the search result record of app, or nil if no apps match the ID,
97
66
/// or an Error if there is a problem with the network request.
98
67
func lookup( app appId: Int ) -> Promise < SearchResult ? > {
99
- let url = MasStoreSearch . lookupURL ( forApp: appId)
68
+ guard let url = lookupURL ( forApp: appId, inCountry: country) else {
69
+ fatalError ( " Failed to build URL for \( appId) " )
70
+ }
100
71
return firstly {
101
72
loadSearchResults ( url)
102
73
} . then { results -> Guarantee < SearchResult ? > in
0 commit comments