Agrega el SDK de Outline a tu app para dispositivos móviles

En este documento, se describe cómo integrar el SDK de Outline en tus aplicaciones para dispositivos móviles, con enfoque en la biblioteca MobileProxy para simplificar la administración de proxy local.

MobileProxy es una biblioteca basada en Go diseñada para optimizar la integración de las funciones de proxy en apps para dispositivos móviles. Utiliza Go Mobile para generar bibliotecas para dispositivos móviles, lo que te permite configurar las bibliotecas de redes de tu app para enrutar el tráfico a través de un proxy local.

App sin MobileProxy

App de contenido sin MobileProxy

App con MobileProxy

App de contenido con MobileProxy

Paso 1: Compila las bibliotecas móviles de MobileProxy

Usa gomobile para compilar el código Go en bibliotecas para Android y iOS.

  1. Clona el repositorio del SDK de Outline:

    git clone https://github.com/Jigsaw-Code/outline-sdk.git
    cd outline-sdk/x
    
  2. Compila los objetos binarios de Go Mobile con go build:

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

    Cómo agregar compatibilidad con Psiphon

    Para agregar compatibilidad para usar la red de Psiphon, sigue estos pasos adicionales:

    • Comunícate con el equipo de Psiphon para obtener una configuración que te brinde acceso a su red. Es posible que se requiera un contrato.
    • Agrega la configuración de Psiphon recibida a la sección fallback de tu configuración SmartDialer.
    • Compila el proxy móvil con la marca -tags psiphon:

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

    La marca -tags psiphon es obligatoria porque la base de código de Psiphon tiene licencia GPL, que puede imponer restricciones de licencia en tu propio código. Te recomendamos que obtengas una licencia especial de ellos.

  3. Genera bibliotecas para dispositivos móviles y agrégalas a tu proyecto:

    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
    

    En Android Studio, selecciona File > Import Project… para importar el paquete out/mobileproxy.aar generado. Para obtener más ayuda, consulta Cómo compilar e implementar en Android de Go Mobile.

    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
    

    Arrastra el paquete out/mobileproxy.xcframework al proyecto de Xcode. Para obtener más ayuda, consulta Compilación e implementación en iOS de Go Mobile.

Paso 2: Ejecuta MobileProxy

Inicializa y, luego, inicia el proxy local MobileProxy dentro del entorno de ejecución de tu app. Puedes usar una configuración de transporte estática o el proxy inteligente para la selección de estrategias dinámicas.

  • Configuración de transporte estático: Usa la función RunProxy con una dirección local y una configuración de transporte.

    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()
    
  • Proxy inteligente: El proxy inteligente selecciona de forma dinámica estrategias de DNS y TLS según dominios de prueba especificados. Debes especificar la estrategia de configuración en formato YAML (ejemplo).

    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()
    

Paso 3: Configura los clientes HTTP y las bibliotecas de redes

Configura tus bibliotecas de red para que usen la dirección y el puerto del proxy local.

HttpClient de Dart/Flutter

Configura el proxy con HttpClient.findProxy.

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

OkHttp (Android)

Configura el proxy con OkHttpClient.Builder.proxy.

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

JVM (Java, Kotlin)

Configura el proxy para usarlo con las propiedades del sistema:

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()))

WebView de Android

Aplica una configuración de proxy a todas las vistas web de tu aplicación con la biblioteca 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
    )

Vista web de iOS

A partir de iOS 17, puedes agregar una configuración de proxy a un WKWebView con su propiedad 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)

Avanzado: Genera una biblioteca para dispositivos móviles personalizada

Para casos de uso avanzados, puedes generar tus propias bibliotecas para dispositivos móviles:

  1. Crea una biblioteca de Go: Desarrolla un paquete de Go que una las funciones requeridas del SDK.
  2. Genera bibliotecas para dispositivos móviles: Usa gomobile bind para producir archivos Android Archive (AAR) y frameworks de Apple. Ejemplos:
  3. Integración en tu app: Agrega la biblioteca generada a tu aplicación para dispositivos móviles.