Android局域网中如何根据已知主机名获取对应IP地址?
Hey there, let's break down how to fix your issues with getting hostnames for known LAN IPs, and work through each problem you're facing:
Why InetAddress.getHostName() Returns IP Instead of Hostname
The methods getHostName() and getCanonicalHostName() rely on reverse DNS (PTR) records, which most home LAN devices don't register with a local DNS server. Additionally, Android's network stack might restrict reverse lookups unless the device has been actively communicated with (like a ping to populate the ARP cache).
Fix for This:
- First, ensure your app has the required permissions in
AndroidManifest.xml:<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> - Try pinging the target IP first to populate the ARP cache, then attempt the hostname lookup. Here's a quick ping implementation snippet:
private boolean pingHost(String ip) { try { Process process = Runtime.getRuntime().exec("ping -c 1 " + ip); int exitCode = process.waitFor(); return exitCode == 0; } catch (IOException | InterruptedException e) { e.printStackTrace(); return false; } } // Usage String targetIp = "192.168.1.100"; if (pingHost(targetIp)) { InetAddress address = InetAddress.getByName(targetIp); String hostname = address.getHostName(); // Use the hostname here }
Why nslookup Doesn't Work in Android
Android's system environment doesn't include nslookup by default on most devices, unlike desktop Java. Calling system commands like this is also unreliable across different Android versions and OEM skins. Instead, use a dedicated DNS library or Android's built-in APIs for DNS queries.
Fixing NoClassDefFoundError for dnsjava
Adding the JAR to the libs directory isn't enough in Android Studio—you need to explicitly declare the dependency in your build file, and handle ProGuard if you're using it:
- Update your app-level
build.gradle:dependencies { // Add this line to include the local JAR implementation files('libs/dnsjava-2.1.7.jar') } - Add ProGuard rules (if enabled):
If you're using code shrinking, add these lines toproguard-rules.proto prevent dnsjava classes from being obfuscated:-keep class org.xbill.** { *; } -keep interface org.xbill.** { *; } - Clean and rebuild your project:
Go toBuild > Clean Project, thenBuild > Rebuild Projectto ensure the dependency is properly linked.
Using dnsjava for Reverse Lookups
Once the library is set up, you can use it to perform reverse DNS queries directly:
import org.xbill.DNS.*; import java.net.InetAddress; public String getHostnameFromIp(String ip) { try { InetAddress address = InetAddress.getByName(ip); Name name = ReverseMap.fromAddress(address); Lookup lookup = new Lookup(name, Type.PTR); Record[] records = lookup.run(); if (records != null && records.length > 0) { return records[0].rdataToString(); } } catch (Exception e) { e.printStackTrace(); } return ip; // Fallback to IP if lookup fails }
Better Alternative: Android's NsdManager (ZeroConf/mDNS)
For LAN device discovery, Android's built-in NsdManager is a more reliable option—it uses mDNS (Bonjour) to find devices that advertise their hostnames on the network. Here's a quick implementation outline:
private NsdManager nsdManager; private NsdManager.DiscoveryListener discoveryListener; private void startDiscovery() { nsdManager = (NsdManager) getSystemService(Context.NSD_SERVICE); discoveryListener = new NsdManager.DiscoveryListener() { @Override public void onDiscoveryStarted(String serviceType) { // Discovery started } @Override public void onServiceFound(NsdServiceInfo serviceInfo) { // Get hostname and IP String hostname = serviceInfo.getServiceName(); InetAddress ip = serviceInfo.getHost(); // Process the device info here } @Override public void onServiceLost(NsdServiceInfo serviceInfo) { // Device lost } @Override public void onDiscoveryStopped(String serviceType) { // Discovery stopped } @Override public void onStartDiscoveryFailed(String serviceType, int errorCode) { // Handle error } @Override public void onStopDiscoveryFailed(String serviceType, int errorCode) { // Handle error } }; nsdManager.discoverServices("_http._tcp.", NsdManager.PROTOCOL_DNS_SD, discoveryListener); } // Don't forget to stop discovery when done private void stopDiscovery() { if (nsdManager != null && discoveryListener != null) { nsdManager.stopServiceDiscovery(discoveryListener); } }
This method doesn't require third-party libraries and works natively on Android, making it a great choice for LAN device hostname/IP mapping.
内容的提问来源于stack exchange,提问作者Hamza Hajeir

