すべてのプロダクト
Search
ドキュメントセンター

Alibaba Cloud DNS:Flutter で HTTPDNS Android/iOS SDK を統合するための実践ガイド

最終更新日:Dec 04, 2025

このドキュメントでは、HTTPDNS の Android および iOS 向け SDK を Flutter プロジェクトに統合する方法について説明します。

概要

Flutter は、Google が開発したモバイル UI フレームワークであり、単一のコードベースから iOS と Android 上で高品質なネイティブインターフェイスを構築できます。Flutter は既存のコードと連携して動作します。無料でオープンソースであり、世界中の開発者や組織に利用されています。Flutter は、独自の仮想マシンを持つ Dart 言語を使用します。Dart コードは、ネイティブコードに AOT (事前) コンパイルされます。これにより、Flutter は中間のブリッジを介さずにプラットフォームと直接通信できるため、効率的なクロスプラットフォームフレームワークとなっています。主な開発シナリオは次の 2 つです。

  • 標準シナリオ

    Flutter プロジェクト全体が Dart で実装されます。コードを一度記述すれば、Android と iOS の両方で実行できます。

  • ハイブリッド開発モデル

    Android または iOS プロジェクトが Flutter をモジュールとして統合します。MethodChannel によって、ネイティブコードと Flutter コード間の呼び出しが可能になります。

警告

Dart の基盤となる HttpClient は、HTTPS 証明書の検証のためのインターフェイスを提供していません。つまり、Dart の HttpClient や、Dio や Http などのサードパーティのネットワークフレームワークを使用して、IP アドレスで直接 HTTPS リクエストを行うことはできません。直接 HTTPS 接続を有効にするには、ローカルプロキシを設定する必要があります。ソケット接続が確立されたら、ホストを HTTPDNS SDK によって名前解決された IP アドレスに置き換えます。これにより、IP アドレスを使用した直接の HTTPS アクセスが可能になります。

Flutter プロジェクトに Android および iOS SDK を統合するための完全なサンプルコードについては、flutterDNSDemo ソースコードをご参照ください。

実装ガイド

Flutter プロジェクトにネイティブ HTTPDNS Android SDK を統合する

  1. Android Studio で Flutter プロジェクトの Android モジュールを開きます。

    Android Studio を起動し、[File] > [Open…] を選択します。

    ご利用の Flutter アプリケーションディレクトリに移動し、android フォルダを選択して [OK] をクリックします。java ディレクトリで、MainActivity.java を開きます。

  2. HTTPDNS Android SDK を Application クラスに統合します:

    HTTPDNS Android SDK の統合方法の詳細については、「Android SDK 開発者ガイド」をご参照ください。

  3. android ディレクトリで、Flutter と通信するための MethodChannel を定義します。チャンネル名は Flutter コード内のものと一致させる必要があります。

package com.example.flutter;

import android.widget.Toast;
import com.alibaba.pdns.DNSResolver;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.embedding.android.FlutterActivity;
import android.content.Context;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import android.util.Log; // Log クラスをインポートします。

public class MainActivity extends FlutterActivity {

    /** ログ識別用の TAG を定義します。 **/
    private static final String TAG = "MainActivity";
    private MethodChannel channel;
    private Context context;
    
    /** これは Flutter のチャンネル名と同じでなければなりません。 **/
    private static final String CHANNEL = "samples.flutter.io/getIP";
    /** Flutter 側がネイティブの Android メソッドを呼び出すためのチャンネルメソッドを定義します。 **/
    private static final String channelMethod = "getIP";
    /** Flutter から Android 側に渡されるパラメーターです。 **/
    private static final String hostArgument = "host";
    /** Alibaba Cloud HTTPDNS Android SDK で提供される DNSResolver オブジェクトを初期化します。 **/
    private DNSResolver dnsResolver = null;

    /** 固定サイズのスレッドプールを作成します。 **/
    private ExecutorService executor = Executors.newFixedThreadPool(5);
    @Override
    public void configureFlutterEngine(FlutterEngine flutterEngine) {
        super.configureFlutterEngine(flutterEngine);
        // DNSResolver を初期化します。
        dnsResolver = DNSResolver.getInstance();
        channel = new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL);
        channel.setMethodCallHandler(new MethodCallHandler() {
            @Override
            public void onMethodCall(MethodCall call, Result result) {
                // すべてのメソッドがここを通過するため、getIP メソッドが呼び出されたかどうかを確認します。
                if (call.method.equals(channelMethod)) {
                    if (call.hasArgument(hostArgument)) {
                        String resolverName = call.argument(hostArgument);

                        Log.d(TAG, "resolverName: " + resolverName); // Log.d を使用してログを出力します。
                        executor.execute(() -> {
                            try {
                                String[] IPArray = dnsResolver.getIpv4ByHostFromCache(resolverName,true);
                                String ip = null;
                                if (IPArray==null || IPArray.length==0){
                                    ip = dnsResolver.getIPV4ByHost(resolverName);
                                }else {
                                    ip = IPArray[0];
                                }
                                String finalIp = ip;
                                runOnUiThread(() -> {
                                    if (finalIp != null) {
                                        Log.d(TAG, "DNS_RESOLUTION_SUCCESS: " + resolverName + "==" + finalIp); // Log.d を使用してログを出力します。
                                        result.success(finalIp);
                                        Toast.makeText(MainActivity.this, "ネイティブ Android のドメイン名名前解決の呼び出しに成功しました!", Toast.LENGTH_SHORT).show();
                                    } else {
                                        Log.e(TAG, "IP アドレスの名前解決中にエラーが発生しました"); // Log.e を使用してエラーログを出力します。
                                        result.error("DNS_RESOLUTION_FAILED", "IP アドレスの名前解決に失敗しました", null);
                                    }
                                });
                            } catch (Exception e) {
                                e.printStackTrace();
                                Log.e(TAG, "IP アドレスの名前解決中にエラーが発生しました", e); // Log.e を使用してエラーログを出力します。
                                runOnUiThread(() -> result.error("DNS_RESOLUTION_FAILED", e.getMessage(), null));
                            }
                        });
                    }
                }
            }
        });
    }
}

Flutter プロジェクトにネイティブ HTTPDNS iOS SDK を統合する

  1. Xcode で Flutter プロジェクトの iOS モジュールを開きます。

    ご利用の Flutter プロジェクトで、ios ディレクトリに移動し、Xcode プロジェクトファイルを開きます。

  2. Xcode プロジェクトに HTTPDNS iOS SDK を統合します。

    HTTPDNS iOS SDK の統合方法の詳細については、「iOS SDK 開発者ガイド」をご参照ください。

  3. iOS コードで、Flutter と通信するための FlutterMethodChannel を定義します:

    FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController;
    FlutterMethodChannel* getIPChannel = [FlutterMethodChannel
                                                methodChannelWithName:@"samples.flutter.io/getIP"
                                                binaryMessenger:controller];// これは Flutter のチャンネル名と同じでなければなりません。
    [getIPChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
            
            if ([@"getIP" isEqualToString:call.method]) {
                NSDictionary *dic = call.arguments;
                NSString *hostName = dic[@"host"];
                NSLog(@"hostName==%@",hostName);
                NSArray *arr = [[DNSResolver share] getIpv4ByCacheWithDomain:hostName andExpiredIPEnabled:YES];
                if (arr != nil && arr.count > 0) {
                    result(arr[0]);
                }else {
                    [[DNSResolver share] getIpv4DataWithDomain:hostName complete:^(NSArray<NSString *> *dataArray) {
                        NSLog(@"array==%@", dataArray);
                        if (dataArray != nil && dataArray.count > 0) {
                            result(dataArray[0]);
                        } else {
                            // 名前解決が失敗した場合、元の hostName を返すことで処理します。
                            result(hostName);
                        }
                    }];
                }
            } else {
                result(FlutterMethodNotImplemented);
            }
        }];
  • MethodChannel とカスタムメソッドを使用した Flutter でのドメイン名名前解決結果の取得

    static const platform = const MethodChannel('samples.flutter.io/getIP');
    final String result = await platform.invokeMethod('getIP', {'host': '名前解決したいドメイン名'});
  • Flutter プロジェクトでの HTTPS リクエストに対する IP アドレス直接接続の使用

    void runPoxyRequest() async {
        var proxy = CustomHttpsProxy();
        final result = await proxy.init();
        print('proxy established: ${result != null}');
        await doHttpGet();
        proxy.close();
    }
    Future doHttpGet() async{
      var httpClient= HttpClient();
      httpClient.findProxy= (uri) => 'PROXY localhost:4041';
      var request= await httpClient.getUrl(Uri.parse('https://www.taobao.com'));
      var response= await request.close();
      // 応答コンテンツを読み取ります。
      var responseBody= await response.transform(Utf8Decoder()).join();
      print(responseBody);
    }

    ソケット接続を確立する際に、ホストを IP アドレスに置き換えることで、直接 HTTPS 接続を有効にします。

    import 'dart:io';
    import 'dart:convert';
    
    import 'package:flutter/services.dart';
    
    class CustomHttpsProxy {
      final int port = 4041;
      ServerSocket? serverSocket;
    
      CustomHttpsProxy();
    
      Future init() async {
        await ServerSocket.bind(InternetAddress.anyIPv4, port).then((serverSocket) {
          this.serverSocket = serverSocket;
          serverSocket.listen((client) {
            try {
              ClientConnectionHandler(client).handle();
            } catch (e) {
              print('ClientConnectionHandler exception $e');
            }
          });
        }).catchError((e) {
          print('serverSocket exception $e');
        });
        return serverSocket;
      }
    
      void close() {
        if (serverSocket != null) {
          serverSocket?.close();
        }
      }
    }
    
    class ClientConnectionHandler {
      final RegExp regx = RegExp(r'CONNECT ([^ :]+)(?::([0-9]+))? HTTP/1.1\r\n');
      static const platform = const MethodChannel('samples.flutter.io/getIP');
      Socket? server;
      Socket? client;
      String content = '';
      String host = '';
      int port = 443;
    
      ClientConnectionHandler(this.client);
    
      void closeSockets() {
    //    print('socket is going to destroy');
        if (server != null) {
          server?.destroy();
        }
        client?.destroy();
      }
    
      Future<void> dataHandler(data) async {
        if (server == null) {
          content += utf8.decode(data);
          final m = regx.firstMatch(content);
          if (m != null) {
            host = m.group(1) ?? 'unknown';
            port = int.tryParse(m.group(2) ?? '') ?? 443;
    
    
    
            final String? resultIP = await platform.invokeMethod('getIP', {'host': host});
            final String realHost = resultIP ?? host;
            print('~~~~~$resultIP');
            try {
              ServerConnectionHandler(realHost, port, this)
                  .handle()
                  .catchError((e) {
                print('Server error $e');
                closeSockets();
              });
            } catch (e) {
              print('Server exception $e');
              closeSockets();
            }
          }
        } else {
          try {
            server?.add(data);
          } catch (e) {
            print('server has been shut down');
            closeSockets();
          }
        }
      }
    
      void errorHandler(error, StackTrace trace) {
        print('client socket error: $error');
      }
    
      void doneHandler() {
        closeSockets();
      }
    
      void handle() {
        client?.listen(dataHandler,
            onError: errorHandler, onDone: doneHandler, cancelOnError: true);
      }
    }
    
    class ServerConnectionHandler {
      final String RESPONSE = 'HTTP/1.1 200 Connection Established\r\n\r\n';
      final String host;
      final int port;
      final ClientConnectionHandler handler;
      Socket? server;
      Socket? client;
      String content = '';
    
      ServerConnectionHandler(this.host, this.port, this.handler) {
        client = handler.client;
      }
    
      // メッセージを受信します。
      void dataHandler(data) {
        try {
          client?.add(data);
        } on Exception catch (e) {
          print('client has been shut down $e');
          handler.closeSockets();
        }
      }
    
      void errorHandler(error, StackTrace trace) {
        print('server socket error: $error');
      }
    
      void doneHandler() {
        handler.closeSockets();
      }
    
      Future handle() async {
        print('Attempting to connect to: $host:$port');
        server = await Socket.connect(host, port, timeout: Duration(seconds: 60));
        server?.listen(dataHandler,
            onError: errorHandler, onDone: doneHandler, cancelOnError: true);
        handler.server = server;
        client?.write(RESPONSE);
      }
    }
説明
  1. このドキュメントは、Flutter プロジェクトで HTTPDNS の Android および iOS 向け SDK を使用する場合にのみ適用されます。

  2. Flutter プロジェクトに HTTPDNS Android および iOS SDK を統合するための完全なサンプルコードについては、「flutterDNSDemo ソースコード」をご参照ください。