Android SDK 統合プロセスドキュメントでは、Android ソフトウェア開発キット (SDK) のインポートと構成、IP アドレスの名前解決、ネットワークライブラリへの適用、および統合の検証を行うための完全なワークフローについて説明します。このトピックでは、HTTPDNS を WebView と統合する方法について説明します。
1. はじめに
WebView は、Web コンテンツをアプリケーションに埋め込む Android システムコンポーネントです。WebView がページを読み込む際に HTTPDNS を使用すると、ネットワークのセキュリティとパフォーマンスを向上させることができます。
このトピックでは、Android WebView のネットワークリクエストに対して、HTTPDNS によって名前解決された IP アドレスを使用する方法に焦点を当てます。HTTPDNS 名前解決サービスに関する詳細については、「Android SDK 統合プロセス」をご参照ください。
2. 現在の技術と課題
2.1 Android WebView のネットワークリクエストの制限
Android では、WebView は Chromium ベースのシステム組み込みのブラウザカーネルを使用して Web ページを読み込みます。そのネットワークリクエストパイプラインは、アプリケーションのネットワークライブラリから独立しています。名前解決もカーネルのネイティブ DNS プロセスを使用します。多くのリクエストは Java レイヤーでインターセプトできません。このクローズドなシステムは、HTTPDNS の統合に対する自然な障壁となっています。
2.2 技術ソリューションの進化
Android システムと WebView の進化に伴い、HTTPDNS を統合するための技術ソリューションも進化しています。
インターセプトソリューション:
このソリューションは、shouldInterceptRequest() コールバックでリソースリクエストをインターセプトし、統合された HTTPDNS 名前解決を持つ OkHttp などのアプリ内ネットワークライブラリを使用して再発行します。このプロセスは、システムの DNS をバイパスします。
このメソッドは実装が簡単で、一部の GET リクエストで機能します。しかし、大きな制限があります。POST などのメソッドのリクエスト本文は公開されていないため、GET リクエストしか完全にインターセプトできません。これにより、このソリューションの WebView 総トラフィックのカバレッジが制限されます。
プロキシソリューション (推奨):
このソリューションは、ローカルプロキシサーバーを起動し、AndroidX WebKit の ProxyController を使用して、WebView 用に統一された HTTP、HTTPS、および WebSocket プロキシを構成します。このメソッドは、すべてのカーネルトラフィックをアプリケーションが制御するネットワークスタックに透過的に転送します。これにより、HTTPDNS 名前解決のためにすべてのプロトコルとリクエストメソッドをインターセプトでき、shouldInterceptRequest() メソッドのカバレッジのボトルネックを克服できます。
3. ローカルプロキシソリューション (推奨)
3.1 ソリューションの概要
このソリューションは、アプリケーション内でローカル HTTP プロキシサーバーを起動します。AndroidX WebKit の `ProxyController` を使用して、すべての WebView ネットワークリクエストをこのローカルプロキシにルーティングします。プロキシは HTTPDNS の名前解決を実行し、リクエストを実際のサーバーに転送します。
ワークフロー:

3.2 依存関係の統合
次の依存関係を app/build.gradle ファイルに追加します。
// 必要に応じて依存関係のバージョンを調整してください
dependencies {
implementation 'androidx.webkit:webkit:1.7.0'
implementation 'com.aliyun.ams:alicloud-android-httpdns:2.6.5'
implementation 'io.github.littleproxy:littleproxy:2.4.4'
implementation 'io.netty:netty-all:4.1.42.Final'
implementation 'com.google.guava:guava:30.1.1-android'
implementation 'org.slf4j:slf4j-android:1.7.30'
}
3.3 統合手順
HTTPDNS WebView プロキシの統合には、3 つのコアステップが含まれます。
ステップ 1: HTTPDNS の初期化
`Application` クラスで HTTPDNS サービスを初期化します。
public class WebviewProxyApplication extends Application {
public static String accountId = "your_account_id";
public static String secretKey = "your_secret_key"; // オプション
@Override
public void onCreate() {
super.onCreate();
initHttpDns();
}
private void initHttpDns() {
try {
InitConfig config = new InitConfig.Builder()
.setContext(this)
.setTimeout(5000)
.setEnableCacheIp(true)
.setEnableExpiredIp(true)
.setSecretKey(secretKey) // オプション、認証用
.build();
HttpDns.init(accountId, config);
Log.i("HTTPDNS", "Initialization successful");
} catch (Exception e) {
Log.e("HTTPDNS", "Initialization failed", e);
}
}
}
ステップ 2: LittleProxy プロキシサービスの開始
`ProxyService` を作成してプロキシサーバーを管理します。
public class ProxyService extends Service {
private HttpProxyServer proxyServer;
private HttpDnsResolver httpDnsResolver;
private boolean isRunning = false;
public boolean startProxyServer() {
if (isRunning) return true;
try {
// HTTPDNS リゾルバーを作成する
httpDnsResolver = new HttpDnsResolver(this);
// LittleProxy サーバーを開始する
int port = generateRandomPort();
proxyServer = DefaultHttpProxyServer.bootstrap()
.withPort(port)
.withAddress(new InetSocketAddress("127.0.0.1", port))
.withServerResolver(httpDnsResolver) // HTTPDNS リゾルバーを使用する
.withConnectTimeout(10000)
.withIdleConnectionTimeout(30000)
.start();
isRunning = true;
Log.i("Proxy", "Proxy server started successfully: 127.0.0.1:" + port);
return true;
} catch (Exception e) {
Log.e("Proxy", "Failed to start proxy server", e);
return false;
}
}
public void stopProxyServer() {
if (proxyServer != null) {
proxyServer.stop();
isRunning = false;
Log.i("Proxy", "Proxy server stopped");
}
}
public boolean isProxyRunning() {
return isRunning;
}
}
// HTTPDNS リゾルバーの実装
class HttpDnsResolver implements HostResolver {
private HttpDnsService httpDnsService;
public HttpDnsResolver(Context context) {
httpDnsService = HttpDns.getService(WebviewProxyApplication.accountId);
}
@Override
public InetSocketAddress resolve(String host, int port) throws UnknownHostException {
try {
// 名前解決に HTTPDNS を使用する
HTTPDNSResult result = httpDnsService.getHttpDnsResultForHostSyncNonBlocking(
host, RequestIpType.auto);
if (result != null && result.getIps() != null && result.getIps().length > 0) {
String ip = result.getIps()[0];
Log.d("DNS", "HTTPDNS resolution: " + host + " -> " + ip);
return new InetSocketAddress(ip, port);
}
// システム DNS にフォールバックする
return new InetSocketAddress(InetAddress.getByName(host), port);
} catch (Exception e) {
Log.w("DNS", "Resolution failed, using system DNS: " + host);
return new InetSocketAddress(InetAddress.getByName(host), port);
}
}
}
ステップ 3: WebView プロキシの構成
Activity で、ローカルプロキシを使用するように WebView を構成します。
public class MainActivity extends AppCompatActivity {
private WebView webView;
private ProxyService proxyService;
private boolean isProxyRunning = false;
// ProxyController 用のメインスレッド Executor
private final Executor mainExecutor = ContextCompat.getMainExecutor(this);
private void configureWebViewProxy() {
// システムがプロキシ構成をサポートしているか確認する
if (!WebViewFeature.isFeatureSupported(WebViewFeature.PROXY_OVERRIDE)) {
Log.w("WebView", "Proxy configuration is not supported on the current system");
return;
}
if (isProxyRunning) {
String proxyAddress = proxyManager.getProxyAddress();
// ローカルプロキシを使用するように WebView を構成する
ProxyConfig proxyConfig = new ProxyConfig.Builder()
.addProxyRule(proxyAddress, ProxyConfig.MATCH_HTTP)
.addProxyRule(proxyAddress, ProxyConfig.MATCH_HTTPS)
.addDirect(ProxyConfig.MATCH_ALL_SCHEMES) // 他のプロトコルは直接接続する
.build();
ProxyController.getInstance().setProxyOverride(proxyConfig, mainExecutor, () -> {
Log.i("WebView", "Proxy configured successfully");
});
} else {
// プロキシ構成をクリアする
ProxyController.getInstance().clearProxyOverride(mainExecutor, () -> {
Log.i("WebView", "Proxy configuration cleared");
});
}
}
private void loadUrl(String url) {
// URL を読み込む前にプロキシ構成が適用されていることを確認する
configureWebViewProxy();
webView.loadUrl(url);
}
}
3.4 完全な実装リファレンス
ローカルプロキシサービスの作成、HTTPDNS の統合、WebView の構成は複雑になる可能性があります。完全なオープンソースの実装が GitHub で入手できます: HTTPDNS WebView Demo。
コアコンポーネントには以下が含まれます。
HttpDnsResolver: LittleProxy の `HostResolver` インターフェイスを実装し、HTTPDNS 名前解決を統合します。
ProxyService: プロキシサーバーのライフサイクルを管理する Android サービスです。
ProxyManager: プロキシのステータスとサービスバインディングを管理します。
MainActivity: UI のインタラクションと WebView プロキシの構成を処理します。
このソリューションには、安定性を確保するための多層のバックオフメカニズムが含まれています。サポートされていないシステムバージョンでは `ProxyController` の構成を自動的にスキップします。HTTPDNS の名前解決が失敗した場合は、システムの DNS にフォールバックします。また、名前解決された IP が利用できない場合は、自動的に別の IP に切り替えます。
4. 従来のインターセプトソリューション
`ProxyController` をサポートしていない古いシステム (WebView < 72) では、従来のインターセプトソリューションをバックオフ戦略として使用できます。
4.1 ソリューションの概要
従来のインターセプトソリューションは、WebViewClient.shouldInterceptRequest() メソッドをオーバーライドして WebView のネットワークリクエストをインターセプトします。その後、統合された HTTPDNS を持つ OkHttp クライアントを使用してリクエストを再発行します。
主な特徴:
GET リクエストのインターセプトのみをサポートします。
Cookie などのデータを手動で処理する必要があります。
実装の複雑さとメンテナンスコストが高くなります。
優れた互換性を提供し、古いバージョンの WebView をサポートします。
4.2 詳細な実装
従来のインターセプトソリューションには、多くの技術的な詳細とエッジケースが含まれます。詳細については、「Android で OkHttp と HTTPDNS を使用するためのベストプラクティス」をご参照ください。
5. 検証
統合が完了したら、ハイジャックシミュレーションや障害注入テストなどの方法を使用して、成功したことを検証できます。詳細な手順については、「ネットワークライブラリ統合の検証」をご参照ください。
6. ソリューションの比較とまとめ
ディメンション / ソリューション | プロキシソリューション | インターセプトソリューション |
公式サポート | Google が AndroidX WebKit で導入した、公式で公開された長期的な API です。 | 公開されている `WebViewClient` API を使用しますが、機能は GET リクエストに限定されます。 |
有効なバージョン | Android 5.0+ WebView 72+ | Android 5.0+ |
プロトコルのカバー率 | HTTP、HTTPS、および WebSocket | HTTP/HTTPS GET リクエストのみ |
実装の複雑さ | 中: ローカルプロキシの実装、ポート管理、双方向転送が必要です。 | 中: OkHttp の統合、リクエストの再構築、DNS 名前解決の処理が必要です。 |
ビジネスコードへの侵入性 | 低: WebView のプロキシを構成するだけで済みます。 | 低: `WebViewClient` の実装を置き換えるだけで済みます。 |
Cookie、キャッシュ、および CORS | プロキシレイヤーで透過的です。追加の処理は不要です。 | 開発者は Cookie を手動で処理する必要があります。 |
メンテナンスコスト | 低: 公式 API に依存しているため、アップグレードの問題のリスクは小さいです。 | 低: 安定した `WebViewClient` API に基づいています。 |
失敗時のバックオフ戦略 | サポート済み: プロキシが失敗した場合、システムのネットワークにフォールバックできます。 | 開発者が実装する必要があります。 |
推奨シナリオ | 完全なプロトコルサポートを必要とする最新のアプリケーション開発。 | 迅速な統合が必要で、GET リクエストのみを処理する必要があるシナリオ。 |
安定性、開発およびメンテナンスコスト、将来のトレンドを考慮すると、ローカルプロキシソリューションを強く推奨します。このソリューションは、すべてのリクエストタイプを処理し、完全なプロトコルサポートを特徴とし、透過的な統合エクスペリエンスを提供し、洗練されたバックオフメカニズムを含みます。低コストで安定した信頼性の高い HTTPDNS サービスを提供します。
ビジネスニーズに基づいて統合戦略を選択してください。ネットワークセキュリティの向上がユーザーエクスペリエンスに悪影響を与えないように、徹底的なテストを実施してください。