在行動應用程式中加入 Outline SDK

本文件說明如何在行動應用程式中整合 Outline SDK,重點介紹如何運用 MobileProxy 程式庫簡化本機 Proxy 管理。

MobileProxy 是用 Go 編寫的程式庫,可協助您輕鬆將 Proxy 功能整合至行動應用程式。這個程式庫會運用 Go Mobile 生成行動程式庫,讓您能設定應用程式的網路程式庫,將流量導向本機 Proxy。

不使用 MobileProxy 的應用程式

不使用 MobileProxy 的內容應用程式

使用 MobileProxy 的應用程式

使用 MobileProxy 的內容應用程式

步驟 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 build 建構 Go Mobile 二進位檔:

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

    新增 Psiphon 支援

    如果想讓應用程式也能使用 Psiphon 網路,的支援,請額外執行下列步驟:

    • 聯絡 Psiphon 團隊,取得可連上他們網路的設定。這可能需要簽訂合約。
    • 將取得的 Psiphon 設定加入 SmartDialer 設定的 fallback 區塊。
    • 使用 -tags psiphon 標記建構 MobileProxy:

      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 中依序選取「檔案」>「匯入專案…」,即可匯入生成的 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 本機 Proxy。您可以使用靜態傳輸設定,或由 Smart Proxy 動態選擇策略。

  • 靜態傳輸設定:使用 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()
    
  • Smart Proxy:Smart Proxy 會根據指定的測試網域,動態選擇 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 用戶端和網路程式庫

請將您的網路程式庫設為使用本機 Proxy 位址和通訊埠。

Dart/Flutter HttpClient

使用 HttpClient.findProxy 設定 Proxy。

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

OkHttp (Android)

使用 OkHttpClient.Builder.proxy 設定 Proxy。

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

JVM (Java、Kotlin)

透過系統屬性設定要使用的 Proxy:

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

使用 androidx.webview 程式庫,將 Proxy 設定套用至應用程式的所有網頁檢視畫面:

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 起,您可以使用 WKWebsiteDataStore 屬性將 Proxy 設定套用至 WKWebView

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 程式庫:開發包含所需 SDK 功能的 Go 套件。
  2. 產生行動程式庫:使用 gomobile bind 產生 Android ARchive (AAR) 和 Apple 框架。範例:
  3. 整合進應用程式:將產生的程式庫加入行動應用程式。