admaDIC App Development & IT Solutions

Swift - Networking - IP Location

by Annett Schwarze | 2025-07-11

The location of an IP-address can be fetched with a very simple request from ip-api.com. With MapKit it is very easy to show it on a map.

The location is fetched from the endpoint `http://ip-api.com/json` using `URLSession.shared.data(from:)`. To decode the JSON some helper type `IPLocation` can be used.

To display the location on a map use a map view from MapKit: `Map(initialPosition:,content:)`.

Note that the request for the IP location uses HTTP and the connection is therefore not encrypted. Beginning with iOS 9 non-encrypted connections must be allowed by adding an App Transport Security exception to the Info.plist file:

        
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
 <key>NSAppTransportSecurity</key>
 <dict>
  <key>NSExceptionDomains</key>
  <dict>
   <key>ip-api.com</key>
   <dict>
    <key>NSExceptionAllowsInsecureHTTPLoads</key>
    <true/>
   </dict>
  </dict>
 </dict>
</dict>
</plist>
    
        
import SwiftUI
import MapKit

struct SampleIPLocationView: View {
    enum Err: Error {
        case invalidURL
        case invalidCoordinates
        case backendError

        var localizedDescription: String {
            switch self {
            case .invalidURL: return "Invalid URL"
            case .invalidCoordinates: return "Invalid coordinates"
            case .backendError: return "Could not load location"
            }
        }
    }

    struct IPLocation: Decodable {
        let status: String
        let country: String
        let regionName: String
        let city: String
        let lat: Double
        let lon: Double
    }

    @State private var ipAddress: String = "8.8.8.8"
    @State private var locationData: IPLocation? = nil
    @State private var isLoading = true
    @State private var errorMessage: String? = nil
    @State private var location: CLLocationCoordinate2D?

    var body: some View {
        VStack(spacing: 16) {
            HStack {
                TextField("IP-Address", text: $ipAddress)
                    .padding(8)
                Button(action: { Task { await fetchLocation() } }, label: { Image(systemName: "mappin.circle") })
                    .padding(8)
            }
            .background {
                Color(white: 0.9)
            }
            .clipShape(RoundedRectangle(cornerRadius: 16))
            if let errorMessage = errorMessage {
                Text("Error: \(errorMessage)").foregroundStyle(.red)
            }
            ZStack {
                Color(white: 0.9)
                if let location = location {
                    VStack {
                        Map(initialPosition: .region(
                            MKCoordinateRegion(
                                center: location,
                                span: MKCoordinateSpan(latitudeDelta: 60, longitudeDelta: 60)
                            )
                        ), content: {
                            Marker("IP: \(ipAddress)", coordinate: location)
                                .tint(.red)
                        })
                        .mapStyle(.hybrid)
                        if let locationData {
                            Form {
                                LabeledContent("City", value: locationData.city)
                                LabeledContent("Region", value: locationData.regionName)
                                LabeledContent("Country", value: locationData.country)
                                LabeledContent("Lat,Lon", value: "\(locationData.lat), \(locationData.lon)")
                            }
                        }
                    }
                } else if isLoading {
                    ProgressView("Fetching ...")
                } else {
                    Text("No position available")
                }
            }
            .clipShape(RoundedRectangle(cornerRadius: 24))
        }
        .navigationTitle("IP Location")
        .navigationBarTitleDisplayMode(.large)
        .task {
            await fetchLocation()
        }
        .padding()
    }

    func fetchLocation() async {
        await MainActor.run {
            isLoading = true
            errorMessage = nil
        }
        do {
            let locationData = try await fetchLocation_impl()
            await MainActor.run {
                if let locationData {
                    self.locationData = locationData
                    location = CLLocationCoordinate2D(latitude: locationData.lat, longitude: locationData.lon)
                }
                isLoading = false
                errorMessage = nil
            }
        } catch {
            await MainActor.run {
                self.errorMessage = error.localizedDescription
                self.isLoading = false
            }
        }
    }

    func fetchLocation_impl() async throws -> IPLocation? {
        guard let url = URL(string: "http://ip-api.com/json/\(ipAddress)") else {
            throw Err.invalidURL
        }
        let (data, _) = try await URLSession.shared.data(from: url)
        let decoder = JSONDecoder()
        let decoded = try decoder.decode(IPLocation.self, from: data)
        if decoded.status == "success" {
            return decoded
        } else {
            throw Err.backendError
        }
    }
}

#Preview {
    SampleIPLocationView()
}
    
Swift Networking IP Location

 

www.admadic.de | webmaster@admadic.de | Legal Notice and Trademarks | Privacy
© 2005-2007 - admaDIC | All Rights Reserved
All other trademarks and/or registered trademarks are the property of their respective owners
Last Change: Fri Jul 11 14:43:45 2025 GMT