Android下主机名到IP映射及本地域名解析无Root方案咨询
Great question—modifying the system /system/etc/hosts file does require root privileges, but there are several reliable workarounds for local DNS resolution on Android that don’t need root access. Let’s dive into the most practical options, along with their use cases and implementation details:
1. Custom DNS Resolver for OkHttp (App-Specific, Easy Setup)
If your app uses OkHttp for network requests, you can directly override the DNS resolution logic to return your desired IP addresses for specific hostnames. This is the simplest approach if OkHttp is your primary networking library.
Implementation Example:
import okhttp3.Dns import okhttp3.OkHttpClient import java.net.InetAddress import java.net.UnknownHostException class CustomDns : Dns { private val customHosts = mapOf( "example.com" to listOf(InetAddress.getByName("192.168.1.100")), "test.dev" to listOf(InetAddress.getByName("10.0.2.2")) ) override fun lookup(hostname: String): List<InetAddress> { return customHosts[hostname] ?: Dns.SYSTEM.lookup(hostname) } } // Use the custom DNS in your OkHttpClient val client = OkHttpClient.Builder() .dns(CustomDns()) .build()
Pros: Minimal code, no permissions required.
Cons: Only applies to OkHttp requests; doesn’t affect WebView or system-level network calls.
2. Wrapped Network Utility Class (Full App Control)
For apps that use a mix of networking libraries or raw HttpURLConnection, you can create a centralized utility class that handles all hostname resolution. This ensures every network call in your app uses your custom mappings.
Implementation Example:
object HostResolver { private val customMappings = mapOf( "example.com" to "192.168.1.100", "test.dev" to "10.0.2.2" ) fun resolve(hostname: String): String { return customMappings[hostname] ?: hostname } } // Usage in network calls: val url = URL("https://${HostResolver.resolve("example.com")}/api/data") val connection = url.openConnection() as HttpURLConnection // ... proceed with connection setup
Pros: Full control over your app’s DNS logic, works with any networking approach you use.
Cons: Requires refactoring existing code to use the utility class; doesn’t intercept system-initiated requests.
3. Local VPN Service (System-Level Interception)
Android’s VPN API allows you to create a local VPN service that routes all your app’s (or the entire device’s) network traffic through your own logic. You can intercept DNS queries here and return custom IP addresses—this works for all network traffic, including WebView and system calls.
Key Implementation Steps:
- Create a class extending
VpnService. - Configure a
VpnService.Builderto set up the VPN tunnel. - Intercept DNS packets and return your custom mappings.
Simplified Code Snippet:
class CustomDnsVpnService : VpnService() { private val customHosts = mapOf( "example.com" to "192.168.1.100" ) override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { val builder = Builder() .addAddress("10.0.0.2", 32) .addRoute("0.0.0.0", 0) .addDnsServer("8.8.8.8") // Fallback DNS .setSession("Custom DNS VPN") val interfaceParcel = builder.establish() ?: return START_NOT_STICKY // Here you'd implement packet interception to handle DNS queries // (Requires reading/writing to the VPN interface file descriptor) return START_STICKY } }
Don’t forget to add the required permission to your AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.BIND_VPN_SERVICE" /> <service android:name=".CustomDnsVpnService" android:permission="android.permission.BIND_VPN_SERVICE"> <intent-filter> <action android:name="android.net.VpnService" /> </intent-filter> </service>
Pros: System-level coverage, works with WebView and all network calls.
Cons: Requires user approval for VPN access, more complex implementation, minor battery overhead.
4. WebView-Specific Overrides
If you need to target WebView specifically, you can use WebSettings to override DNS behavior (available on Android 11+):
webView.settings.dnsOverHttpsServer = "https://your-custom-dns-server.com" // Or for static mappings, use a local DNS server via VPN or a custom content provider
Alternatively, you can inject JavaScript into the WebView to rewrite URLs before they’re loaded, pointing to your target IP addresses.
内容的提问来源于stack exchange,提问作者Muhammad Rashid Mahmood

