18

I found this sample code to get all local IP addresses, but I don't find an easy solution to get the public IP.

A legacy class from Apple allowed to do that ... but it's legacy ...

picciano
  • 22,341
  • 9
  • 69
  • 82
Damien Romito
  • 9,801
  • 13
  • 66
  • 84

9 Answers9

23

It's as simple as this:

NSString *publicIP = [NSString stringWithContentsOfURL:[NSURL URLWithString:@"https://icanhazip.com/"] encoding:NSUTF8StringEncoding error:nil];
publicIP = [publicIP stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]]; // IP comes with a newline for some reason
Tarek
  • 2,372
  • 2
  • 23
  • 35
  • 1
    it works, it's short and simple way to get ip address !! thanks – Shikha Sharma Dec 23 '16 at 05:47
  • 6
    Hahaha. I don't know how much I trust the longevity of a site with the domain `icanhazip.com`. :) – CIFilter Mar 07 '17 at 21:16
  • 5
    `icanhazip.com` is actually a really well known service by a Backspace employee and has been running for many years now (at least 7). For more info, check this link out: [icanhazip FAQ](https://major.io/icanhazip-com-faq/) – Tarek Mar 21 '17 at 00:31
  • in Swift I answered [here](https://stackoverflow.com/a/63280838/11079607) – Taras Aug 06 '20 at 09:40
9

I have used ALSystemUtilities in the past. You basically have to make a call externally to find this out.

+ (NSString *)externalIPAddress {
    // Check if we have an internet connection then try to get the External IP Address
    if (![self connectedViaWiFi] && ![self connectedVia3G]) {
        // Not connected to anything, return nil
        return nil;
    }

    // Get the external IP Address based on dynsns.org
    NSError *error = nil;
    NSString *theIpHtml = [NSString stringWithContentsOfURL:[NSURL URLWithString:@"http://www.dyndns.org/cgi-bin/check_ip.cgi"]
                                                   encoding:NSUTF8StringEncoding
                                                      error:&error];
    if (!error) {
        NSUInteger  an_Integer;
        NSArray *ipItemsArray;
        NSString *externalIP;
        NSScanner *theScanner;
        NSString *text = nil;

        theScanner = [NSScanner scannerWithString:theIpHtml];

        while ([theScanner isAtEnd] == NO) {

            // find start of tag
            [theScanner scanUpToString:@"<" intoString:NULL] ;

            // find end of tag
            [theScanner scanUpToString:@">" intoString:&text] ;

            // replace the found tag with a space
            //(you can filter multi-spaces out later if you wish)
            theIpHtml = [theIpHtml stringByReplacingOccurrencesOfString:
                         [ NSString stringWithFormat:@"%@>", text]
                                                             withString:@" "] ;
            ipItemsArray = [theIpHtml  componentsSeparatedByString:@" "];
            an_Integer = [ipItemsArray indexOfObject:@"Address:"];
            externalIP =[ipItemsArray objectAtIndex:++an_Integer];
        }
        // Check that you get something back
        if (externalIP == nil || externalIP.length <= 0) {
            // Error, no address found
            return nil;
        }
        // Return External IP
        return externalIP;
    } else {
        // Error, no address found
        return nil;
    }
}

Source from ALSystemUtilities

Andrei
  • 2,607
  • 1
  • 23
  • 26
  • We cannot find it without call? – Damien Romito Dec 30 '14 at 16:37
  • 9
    If by "public IP" you mean "IP address that the Internet will see me as coming from" then that is not possible to know without asking some part of the Internet. NAT does not occur on your device; it occurs on the network. Note that different devices may see you as having a different IP depending on how you route to them (including the possibility that some may see you as having an IPv4 address and other see you with an IPv6 address). "The Internet" is just one particular network; you can be on and route between many different networks w/ different IP mappings. – Rob Napier Dec 30 '14 at 17:46
7

Thanks @Tarek for his answer

Here, code in Swift 4 version

func getPublicIPAddress() -> String {
    var publicIP = ""
    do {
        try publicIP = String(contentsOf: URL(string: "https://www.bluewindsolution.com/tools/getpublicip.php")!, encoding: String.Encoding.utf8)
        publicIP = publicIP.trimmingCharacters(in: CharacterSet.whitespaces)
    }
    catch {
        print("Error: \(error)")
    }
    return publicIP
}

NOTE1: To get public IP address, we must have external site to return public IP. The website I use is business company website, so, it will be their until the business gone.

NOTE2: You can made some site by yourself, however, Apple require HTTPS site to be able to use this function.

Sruit A.Suk
  • 7,073
  • 7
  • 61
  • 71
2

For those of us using Swift, here's my translation of Andrei's answer with the addition of NSURLSession to run it in the background. To check the network, I use Reachability.swift. Also, remember to add dyndns.org to NSExceptionDomains for NSAppTransportSecurity in your info.plist.

var ipAddress:String?
func getIPAddress() {

    if reachability!.isReachable() == false {
        return
    }

    guard let ipServiceURL = NSURL(string: "http://www.dyndns.org/cgi-bin/check_ip.cgi") else {
        return
    }

    let session = NSURLSession.sharedSession()

    let task = session.dataTaskWithURL(ipServiceURL, completionHandler: {(data, response, error) -> Void in
        if error != nil {
            print(error)
            return
        }

        let ipHTML = NSString(data: data!, encoding: NSUTF8StringEncoding) as? String

        self.ipAddress = self.scanForIPAddress(ipHTML)

    })

    task.resume()
}

func scanForIPAddress(var ipHTML:String?) -> String? {

    if ipHTML == nil {
        return nil
    }

    var externalIPAddress:String?
    var index:Int?
    var ipItems:[String]?
    var text:NSString?

    let scanner = NSScanner(string: ipHTML!)

    while scanner.atEnd == false {
        scanner.scanUpToString("<", intoString: nil)

        scanner.scanUpToString(">", intoString: &text)

        ipHTML = ipHTML!.stringByReplacingOccurrencesOfString(String(text!) + ">", withString: " ")

        ipItems = ipHTML!.componentsSeparatedByString(" ")

        index = ipItems!.indexOf("Address:")
        externalIPAddress = ipItems![++index!]

    }

    if let ip = externalIPAddress {
        print("External IP Address: \(ip)")
    }

    return externalIPAddress

}
blwinters
  • 1,911
  • 19
  • 40
2

I use ipify and with no complaints.

NSURL *url = [NSURL URLWithString:@"https://api.ipify.org/"];
NSString *ipAddress = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
NSLog(@"My public IP address is: %@", ipAddress);
Ahmed Khedr
  • 1,053
  • 1
  • 11
  • 24
2

In case you want to retrieve IP asynchronously, there is a way to do that using ipify.org and Alamofire in 1 line of code:

Alamofire.request("https://api.ipify.org").responseString { (response) in
    print(response.result.value ?? "Unable to get IP")
}
Arthur Shkil
  • 362
  • 2
  • 12
1

You can call a public IP address lookup services to get this? I have set up http://ipof.in as a service that returns the device IP address as JSON / XML or plain text. You can find them here

For JSON with GeoIP data

http://ipof.in/json

https://ipof.in/json

For XML response

http://ipof.in/xml

https://ipof.in/xml

For plain text IP address

http://ipof.in/txt

https://ipof.in/txt

vivekv
  • 2,238
  • 3
  • 23
  • 37
0

You have to query an external server to find out the public IP. Either set up your own server (1 line of php code) or use one of the many available ones which return the IP as plain text or json upon http query. Like for example http://myipdoc.com/ip.php .

0

I find both Andrei and Tarek's answers helpful. Both are relying a web URL to query the "public IP" of the iOS/OS X device.

However, there is an issue with this approach in some part of the world where URL such as "http://www.dyndns.org/cgi-bin/check_ip.cgi" is censored as in andrei's answer:

NSString *theIpHtml = [NSString stringWithContentsOfURL:[NSURL URLWithString:@"http://www.dyndns.org/cgi-bin/check_ip.cgi"]
encoding:NSUTF8StringEncoding
                                                  error:&error];

In this case, we will need to use an "uncensored" URL within the region such as http://1212.ip138.com/ic.asp

Note that the web URL could use a different HTML and encoding than what Andrei's answer could parse - in the URL above, some very gentle changes can fix it by using kCFStringEncodingGB_18030_2000 for http://1212.ip138.com/ic.asp

NSURL* externalIPCheckURL = [NSURL URLWithString: @"http://1212.ip138.com/ic.asp"];
encoding:NSUTF8StringEncoding error:nil];

NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);

NSString *theIpHtml = [NSString stringWithContentsOfURL: externalIPCheckURL
                                                   encoding: encoding
                                                      error: &error];
jose920405
  • 7,982
  • 6
  • 45
  • 71
Yushen
  • 16
  • 2
  • Hi Yushen; this is useful information, but isn't a complete answer in itself - so it should really be posted as a comment on one or both of the other answers you refer to. At the moment, you don't have enough reputation to make comments; for now, you need to work on posting useful questions and useful complete answers to earn the reputation to add comments. – Vince Bowdren Aug 16 '16 at 11:32