Как добавить Outline SDK в мобильное приложение

В этом руководстве описывается, как интегрировать Outline SDK в мобильные приложения с использованием библиотеки MobileProxy, которая упрощает работу с локальным прокси-сервером.

MobileProxy – это библиотека на основе языка Go. Она упрощает интеграцию функций прокси-сервера в мобильные приложения. Библиотека использует инструмент Go Mobile для генерирования мобильных библиотек. Это позволяет настраивать сетевые библиотеки приложения так, чтобы трафик проходил через локальный прокси-сервер.

Приложение без MobileProxy

Приложение для работы с контентом без MobileProxy

Приложение с MobileProxy

Приложение для работы с контентом с MobileProxy3

Шаг 1. Создайте мобильные библиотеки MobileProxy

Используйте gomobile, чтобы скомпилировать код Go в библиотеки для Android и iOS.

  1. Клонируйте хранилище Outline SDK:

    git clone https://github.com/Jigsaw-Code/outline-sdk.git
    cd outline-sdk/x
    
  2. Соберите исполняемые файлы Go Mobile с помощью команды go build:

    go build -o "$(pwd)/out/" golang.org/x/mobile/cmd/gomobile golang.org/x/mobile/cmd/gobind
    

    Как добавить поддержку Psiphon

    Вы можете добавить поддержку сети Psiphon, выполнив следующие дополнительные шаги:

    • Свяжитесь с командой Psiphon, чтобы получить конфигурацию для доступа к их сети. Возможно, для этого потребуется заключить договор.
    • Добавьте полученную конфигурацию Psiphon в раздел fallback конфигурации SmartDialer.
    • Соберите Mobile Proxy с пометкой -tags psiphon:

      go build -tags psiphon -o "$(pwd)/out/" golang.org/x/mobile/cmd/gomobile golang.org/x/mobile/cmd/gobind
      

    Пометка -tags psiphon обязательна, поскольку код Psiphon доступен по лицензии GPL, которая может накладывать лицензионные ограничения на ваш код. Рассмотрите возможность получения специальной лицензии у команды Psiphon.

  3. Как создать мобильные библиотеки и добавить их в проект

    Android

    PATH="$(pwd)/out:$PATH" gomobile bind -ldflags='-s -w' -target=android -androidapi=21 -o "$(pwd)/out/mobileproxy.aar" github.com/Jigsaw-Code/outline-sdk/x/mobileproxy
    

    В Android Studio выберите File > Import Project… (Файл > Импортировать проект…), чтобы импортировать сгенерированный пакет out/mobileproxy.aar. Дополнительная информация приведена в разделе Go Mobile на странице Сборка и развертывание для Android.

    iOS

    PATH="$(pwd)/out:$PATH" gomobile bind -ldflags='-s -w' -target=ios -iosversion=11.0 -o "out/mobileproxy.xcframework" github.com/Jigsaw-Code/outline-sdk/x/mobileproxy
    

    Перетащите пакет out/mobileproxy.xcframework в проект Xcode. Дополнительная информация приведена в разделе Go Mobile на странице Сборка и развертывание для iOS.

Шаг 2. Запустите MobileProxy

Инициализируйте и запустите локальный прокси-сервер MobileProxy в среде выполнения вашего приложения. Вы можете использовать статическую конфигурацию протокола или SmartProxy для динамического выбора стратегии.

  • Статическая конфигурация протокола: используйте функцию RunProxy, указав локальный адрес и параметры конфигурации протокола.

    Android

    import mobileproxy.*
    
    val dialer = StreamDialer("split:3")
    
    // Use port zero to let the system pick an open port for you.
    val proxy = Mobileproxy.runProxy("localhost:0", dialer)
    // Configure your networking library using proxy.host() and proxy.port() or proxy.address().
    // ...
    // Stop running the proxy.
    proxy.stop()
    

    iOS

    import Mobileproxy
    
    let dialer = MobileproxyStreamDialer("split:3")
    
    // Use port zero to let the system pick an open port for you.
    let proxy = MobileproxyRunProxy("localhost:0", dialer)
    // Configure your networking library using proxy.host() and proxy.port() or proxy.address().
    // ...
    // Stop running the proxy.
    proxy.stop()
    
  • SmartProxy: эта технология динамически выбирает стратегии DNS и TLS на основе заданных тестовых доменов. Стратегию конфигурации необходимо указать в формате YAML (пример).

    Android

    val testDomains = Mobileproxy.newListFromLines("www.youtube.com\ni.ytimg.com")
    val strategiesConfig = "..."  // Config YAML.
    val dialer = Mobileproxy.newSmartStreamDialer(testDomains, strategiesConfig, Mobileproxy.newStderrLogWriter())
    
    // Use port zero to let the system pick an open port for you.
    val proxy = Mobileproxy.runProxy("localhost:0", dialer)
    // Configure your networking library using proxy.host() and proxy.port() or proxy.address().
    // ...
    // Stop running the proxy.
    proxy.stop()
    

    iOS

    import Mobileproxy
    
    var dialerError: NSError?
    let testDomains = MobileproxyNewListFromLines("www.youtube.com\ni.ytimg.com")
    let strategiesConfig = "..."  // Config YAML.
    let dialer = MobileproxyNewSmartStreamDialer(
        testDomains,
        strategiesConfig,
        MobileproxyNewStderrLogWriter(),
        &dialerError
    )
    
    var proxyError: NSError?
    // Use port zero to let the system pick an open port for you.
    MobileproxyRunProxy("localhost:0", dialer, &proxyError)
    // Configure your networking library using proxy.host() and proxy.port() or proxy.address().
    // ...
    // Stop running the proxy.
    proxy.stop()
    

Шаг 3. Настройте HTTP-клиенты и сетевые библиотеки

Настройте сетевые библиотеки на использование локального адреса и порта прокси-сервера.

Dart/Flutter HttpClient

Установите прокси-сервер с помощью HttpClient.findProxy.

HttpClient client = HttpClient();
client.findProxy = (Uri uri) {
  return "PROXY " + proxy.address();
};

OkHttp (Android)

Установите прокси-сервер с помощью OkHttpClient.Builder.proxy.

val proxyConfig = Proxy(Proxy.Type.HTTP, InetSocketAddress(proxy.host(), proxy.port()))
val client = OkHttpClient.Builder().proxy(proxyConfig).build()

JVM (Java, Kotlin)

Настройте прокси-сервер с использованием системных свойств:

System.setProperty("http.proxyHost", proxy.host())
System.setProperty("http.proxyPort", String.valueOf(proxy.port()))
System.setProperty("https.proxyHost", proxy.host())
System.setProperty("https.proxyPort", String.valueOf(proxy.port()))

Android WebView

Примените конфигурацию прокси-сервера ко всем WebView в приложении с помощью библиотеки androidx.webview:

ProxyController.getInstance()
    .setProxyOverride(
        ProxyConfig.Builder()
            .addProxyRule(this.proxy!!.address())
            .build(),
        {}, // execution context for the following callback - do anything needed here once the proxy is applied, like refreshing web views
        {} // callback to be called once the ProxyConfig is applied
    )

iOS WebView

Начиная с iOS 17 и более поздних версий вы можете добавить прокси-конфигурацию для WKWebView, используя свойство WKWebsiteDataStore:

let configuration = WKWebViewConfiguration()
let endpoint = NWEndpoint.hostPort(host: NWEndpoint.Host(proxyHost), port: NWEndpoint.Port(proxyPort)!)
let proxyConfig = ProxyConfiguration.init(httpCONNECTProxy: endpoint)
let websiteDataStore = WKWebsiteDataStore.default()
websiteDataStore.proxyConfigurations = [proxyConfig]
let webview = WKWebView(configuration: configuration)

Как создать собственную мобильную библиотеку (расширенная настройка)

Если требуется расширенная настройка, вы можете сгенерировать собственные мобильные библиотеки.

  1. Создайте библиотеку на основе языка Go: разработайте Go-пакет, включающий нужные функции SDK.
  2. Сгенерируйте мобильные библиотеки: используйте gomobile bind для создания Android ARchive (AAR) и Apple Framework. Примеры:
  3. Интегрируйте сгенерированную библиотеку в мобильное приложение.