본문 바로가기

Android

[Android] Public IP 사용

login history를 따로 작업해야하는 일이 생겼다.

 

원래는 서버에서 ip가져오는 작업을 해서 처리하려했으나 네트워크, 서버 구조상 계속 내부주소가 찍히는 문제가 발생했다.^^

 

그렇게 나의 3일 방황기가 시작되었따...

 

android에서 ip가져오는 건 단 한번의 검색으로 쉽게 작업했다.

 

스택오버플로에서 따온 코드를 살짝 수정만으로도 잘나와서 잘못된 코드인줄도 몰랐다.

아 잘못된 코드는 아니지 목적에 맞지않는 코드였을 뿐.

 

public ip를 가져와야하는데 로그를 찍으면 로컬네트워크로 찍힌다. 로컬네트워크라는 것도 ipv6을 ipv4로 변환해보고나서야 알았다.(ipv6 -> ipv4로 변환은 주소체계가 달라서 안될 수도 있다.)

 

아래는 그에 대한 코드이다. (주의! 로컬네트워크 주소가져오는 코드임)

public class IPAddressUtil {
    public String getIPAddress(Context context) {
        String ip = null;
        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        if (cm != null) {
            Network network = cm.getActiveNetwork();
            if (network != null) {
                NetworkCapabilities nc = cm.getNetworkCapabilities(network);
                if (nc != null) {
                    if (nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
                        ip = getWifiIPAddress(context);
                    } else if (nc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
                        ip = getMobileIPAddress();
                    }
                }
            }
        }
        return ip;
    }

    private String getWifiIPAddress(Context context) {
        WifiManager wm = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
        if (wm != null) {
            int ip = wm.getConnectionInfo().getIpAddress();
            return String.format(
                    "%d.%d.%d.%d",
                    (ip & 0xff),
                    (ip >> 8 & 0xff),
                    (ip >> 16 & 0xff),
                    (ip >> 24 & 0xff)
            );
        }
        return null;
    }

    private String getMobileIPAddress() {
        try {
            List<NetworkInterface> interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
            for (NetworkInterface intf : interfaces) {
                List<InetAddress> addrs = Collections.list(intf.getInetAddresses());
                for (InetAddress addr : addrs) {
                    if (!addr.isLoopbackAddress()) {
                        String sAddr = addr.getHostAddress();
                        boolean isIPv4 = sAddr.indexOf(':') < 0;
                        if (isIPv4) {
                            return sAddr; // IPv4 주소 반환
                        } else {
                            // IPv6 주소의 Zone ID 제거
                            int zoneIndex = sAddr.indexOf('%');
                            if (zoneIndex > 0) {
                                sAddr = sAddr.substring(0, zoneIndex);
                            }
                         
                            if (!sAddr.startsWith("fe80::")) {
                                return sAddr; // 유효한 IPv6 주소 반환
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

 

그래서 검색하다가 나온 ipify-android

https://github.com/chintan369/Ipify-Android

 

GitHub - chintan369/Ipify-Android: Ipify allows users to get current public IP address for connected network in real-time

Ipify allows users to get current public IP address for connected network in real-time - chintan369/Ipify-Android

github.com

 

이 라이브러리 좋으다.

 

다만 Java프로젝트에서 사용하려면 아래와 같이 추가해주자.

// build.gradle (Project)
plugins {
	...
    id 'org.jetbrains.kotlin.android' version '1.6.21' apply false
}

// build.gradle (App)

plugins {
	...
    id 'kotlin-android'
}

implementation 'com.github.chintan369:Ipify-Android:1.0.1'


//클래스
Ipfy.Companion.init(this.context, IpfyClass.UniversalIP);
Ipfy.Companion.getInstance1().getPublicIpObserver().observe(this, ipAddressData -> {
	ip = ipAddressData.getCurrentIpAddress();
});

 

하지만 이 또한 문제가 있었는데 ipv4 주소는 가져오지 못하는 것이였다.

 

우리는 1번으로 ipv4 주소 저장이고 null값일 때 ipv6를 저장하는 것이 목표였기때문에

 

코드에 단 몇줄만 추가하면되는 저 간단한 라이브러리를 사용할 수 없었다. =_=....

 

최종으로 사용한 코드는 바로 이것이다.

public class PublicIPThread {
    public void execute() {
        Thread thread = new Thread(() -> {
            try {
                String ipAddress = fetchIPAddress("https://api4.my-ip.io/v2/ip.txt");

                if (ipAddress == null || ipAddress.isEmpty()) {
                    ipAddress = fetchIPAddress("https://api.my-ip.io/v2/ip.txt");
                }

                if (ipAddress != null && !ipAddress.isEmpty()) {
                    Logger.d(ipAddress);
                } else {
                    mainActivity.ip = "";
                    Logger.e("IP is empty");

                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        thread.start();
    }

    private String fetchIPAddress(String urlString) throws IOException {
        try (Scanner scnr = new Scanner(new URL(urlString).openStream(), "UTF-8").useDelimiter("\\A")) {
            if (scnr.hasNext()) {
                return scnr.nextLine();
            } else {
                return null;
            }
        }
    }
}

그래도 간략한 편이다. 

 

이번에 ip가져오는 로직을 짜면서 공부한 것인데

 

모바일에서 lte일 때 가져온 ip로는 현재 사용자의 위치를 표기하지 못한다.

 

대부분 이동통신사 위치를 가르킨다. (그래도 통신사 내부에 기록이 남는다고 한다)

 

또 현재 내 아이피는 구글에 쳐보거나 whatismyipaddress라는 페이지에 가도 알 수 있지만 

 

삼성 휴대폰이라면 히든메뉴를 통해 알 수도 있다. (https://m.blog.naver.com/superjini75/222075645718)

 

 

 

 

참고

https://stackoverflow.com/questions/59818891/how-to-get-public-ip-address-of-android-device-programmatically

https://github.com/chintan369/Ipify-Android

https://namu.wiki/w/%ED%86%B5%EC%8B%A0%EC%82%AC%20IP

 

 

'Android' 카테고리의 다른 글

[Flutter] 설치  (0) 2025.04.22