הוספת 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. יוצרים את קובצי ה-binaries של 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.
    • יוצרים את שרת ה-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, שעלול להטיל הגבלות רישיון על הקוד שלכם. מומלץ לקבל מהם רישיון מיוחד.

  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 שנוצרה. לקבלת עזרה נוספת, אפשר לעיין במאמר פיתוח ופריסה ל-Android באתר 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
    

    גוררים את החבילה out/mobileproxy.xcframework אל פרויקט Xcode. למידע נוסף, קראו את המאמר פיתוח ופריסה ל-iOS ב-Go Mobile.

שלב 2: מפעילים את MobileProxy

מאתחלים ומפעילים את שרת ה-proxy המקומי MobileProxy בסביבת זמן הריצה של האפליקציה. אפשר להשתמש בתצורת תעבורה סטטית או בשרת 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()
    
  • שרת proxy חכם: שרת ה-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

מגדירים את שרת ה-proxy באמצעות HttpClient.findProxy.

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

OkHttp ‏ (Android)

מגדירים את שרת ה-proxy באמצעות OkHttpClient.Builder.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 Web View

מחילים הגדרת שרת proxy על כל תצוגות האינטרנט באפליקציה באמצעות הספרייה 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 Web View

החל מ-iOS 17, אפשר להוסיף הגדרת שרת proxy ל-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 Archives‏ (AAR) ותבניות של Apple. דוגמאות:
  3. שילוב באפליקציה: מוסיפים את הספרייה שנוצרה לאפליקציה לנייד.