Flutter隐私保护插件tor的使用

发布于 1周前 作者 nodeper 来自 Flutter

Flutter隐私保护插件tor的使用

foundation-Devices/tor 是一个多平台的Flutter插件,用于管理Tor代理。基于 arti 项目。本文将详细介绍如何在Flutter项目中使用该插件,并提供一个完整的示例demo。

开始之前

安装Rust

请确保安装了Rust工具链,建议使用 rustup 而不是 homebrew 进行安装。

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

安装cargo-ndk

cargo install cargo-ndk

Cargokit

Cargokit用于构建项目,只需运行 flutter run 或者在Android Studio或VS Code中运行(未测试)。

更新Cargokit时,可以使用以下命令:

git subtree pull --prefix cargokit https://github.com/irondash/cargokit.git main --squash

开发

为了重新生成Dart绑定,请运行:

just generate

示例应用

example 目录下运行 flutter run 来启动示例应用。具体使用方法请参考 example/lib/main.dart 文件。

示例代码

以下是一个完整的示例代码,展示如何在Flutter应用中使用Tor插件。

// SPDX-FileCopyrightText: 2023 Foundation Devices Inc.
// SPDX-FileCopyrightText: 2024 Foundation Devices Inc.
//
// SPDX-License-Identifier: MIT

import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:socks5_proxy/socks_client.dart'; // Just for example; can use any socks5 proxy package, pick your favorite.
import 'package:tor/tor.dart';
import 'package:tor/socks_socket.dart'; // For socket connections

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: Home(),
    );
  }
}

class Home extends StatefulWidget {
  const Home({super.key});

  @override
  State<Home> createState() => _MyAppState();
}

class _MyAppState extends State<Home> {
  bool torStarted = false;
  final hostController = TextEditingController(text: 'https://icanhazip.com/');

  Future<void> startTor() async {
    await Tor.init();
    await Tor.instance.start();
    setState(() {
      torStarted = Tor.instance.started;
    });
    print('Done awaiting; tor should be running');
  }

  @override
  void dispose() {
    hostController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    const spacerSmall = SizedBox(height: 10);
    return Scaffold(
      appBar: AppBar(
        title: const Text('Tor example'),
      ),
      body: SingleChildScrollView(
        child: Container(
          padding: const EdgeInsets.all(10),
          child: Column(
            children: [
              Row(
                children: [
                  TextButton(
                    onPressed: torStarted
                        ? null
                        : () async {
                            unawaited(
                              showDialog(
                                barrierDismissible: false,
                                context: context,
                                builder: (_) => const Dialog(
                                  child: Padding(
                                    padding: EdgeInsets.all(20.0),
                                    child: Text("Starting tor..."),
                                  ),
                                ),
                              ),
                            );

                            final time = DateTime.now();
                            print("NOW: $time");
                            await startTor();
                            print("Starting tor took "
                                "${DateTime.now().difference(time).inSeconds} "
                                "seconds. Proxy running on port ${Tor.instance.port}");

                            if (mounted) {
                              Navigator.of(context).pop();
                            }
                          },
                    child: const Text("Start"),
                  ),
                  TextButton(
                    onPressed: !torStarted
                        ? null
                        : () async {
                            await Tor.instance.stop();
                            setState(() {
                              torStarted = false;
                            });
                          },
                    child: const Text("Stop"),
                  ),
                ],
              ),
              Row(
                children: [
                  Expanded(
                    child: TextField(
                      controller: hostController,
                      decoration: const InputDecoration(
                        border: OutlineInputBorder(),
                        hintText: 'Host to request',
                      ),
                    ),
                  ),
                  spacerSmall,
                  TextButton(
                    onPressed: torStarted
                        ? () async {
                            final client = HttpClient();
                            SocksTCPClient.assignToHttpClient(client, [
                              ProxySettings(InternetAddress.loopbackIPv4,
                                  Tor.instance.port, password: null),
                            ]);

                            final url = Uri.parse(hostController.text);
                            final request = await client.getUrl(url);
                            final response = await request.close();
                            var responseString =
                                await utf8.decodeStream(response);
                            print(responseString);

                            client.close();
                          }
                        : null,
                    child: const Text("Make proxied request"),
                  ),
                ],
              ),
              spacerSmall,
              TextButton(
                onPressed: torStarted
                    ? () async {
                        var socksSocket = await SOCKSSocket.create(
                          proxyHost: InternetAddress.loopbackIPv4.address,
                          proxyPort: Tor.instance.port,
                          sslEnabled: true,
                        );

                        await socksSocket.connect();
                        await socksSocket.connectTo('bitcoin.stackwallet.com', 50002);
                        await socksSocket.sendServerFeaturesCommand();
                        await socksSocket.close();
                      }
                    : null,
                child: const Text(
                  "Connect to bitcoin.stackwallet.com:50002 (SSL) via socks socket",
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

通过上述代码,您可以在Flutter应用中集成Tor插件,实现隐私保护功能。希望这个示例能够帮助您更好地理解和使用Tor插件。


更多关于Flutter隐私保护插件tor的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter隐私保护插件tor的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter项目中集成Tor以增强隐私保护是一个复杂但有趣的任务。Tor网络通过多层加密和路由来隐藏用户的身份和位置。为了在Flutter中使用Tor,通常需要借助一些原生插件或者与原生代码进行交互。由于Flutter本身不直接支持Tor,我们需要借助一些原生库(如libtor)和一些桥接库来实现这一功能。

以下是一个简化的示例,展示如何在Flutter项目中通过MethodChannel与原生代码交互,以启动和管理Tor服务。请注意,这只是一个基础示例,实际应用中需要处理更多的细节和异常情况。

1. 设置Flutter项目

首先,创建一个新的Flutter项目:

flutter create tor_flutter_app
cd tor_flutter_app

2. 添加原生依赖

iOS

ios/Podfile中添加对libtor的依赖(注意:libtor可能不是CocoaPods的官方库,这里假设有一个可用的Pod或者你需要手动集成)。由于Tor在iOS上的集成相对复杂,这里我们假设你已经有一个可用的Tor库,并将其集成到你的iOS项目中。

你可能需要手动将Tor的二进制文件和相关库添加到Xcode项目中,并配置好相关的搜索路径和链接器标志。

Android

android/app/build.gradle中添加对Tor的依赖(同样,这里假设有一个可用的Gradle依赖,如果没有,你可能需要手动下载并集成):

dependencies {
    implementation 'org.torproject:libtor:some-version' // 假设有这样的依赖
}

然后,在android/app/src/main/jniLibs/目录下添加对应架构的Tor库文件(如armeabi-v7a/libtor.so)。

3. 创建原生代码桥接

iOS

ios/Runner/目录下创建一个新的Swift或Objective-C文件,比如TorManager.swift,用于管理Tor服务:

import Foundation

@objc class TorManager: NSObject {
    static let shared = TorManager()
    private let channel = FlutterMethodChannel(name: "com.example.tor_flutter_app/tor", binaryMessenger: nil)
    
    private init() {
        super.init()
        setupTor()
        channel.setMethodCallHandler { call, result in
            switch call.method {
            case "startTor":
                self.startTor { success in
                    result(success as Any)
                }
            case "stopTor":
                self.stopTor { success in
                    result(success as Any)
                }
            default:
                result(FlutterMethodNotImplemented)
            }
        }
    }
    
    private func setupTor() {
        // 初始化Tor的代码
    }
    
    private func startTor(completion: @escaping (Bool) -> Void) {
        // 启动Tor的代码
        completion(true) // 假设启动成功
    }
    
    private func stopTor(completion: @escaping (Bool) -> Void) {
        // 停止Tor的代码
        completion(true) // 假设停止成功
    }
}

AppDelegate.swift中注册这个通道:

import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        GeneratedPluginRegistrant.register(with: self)
        TorManager.shared.channel.setBinaryMessenger(self.binaryMessenger)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }
}

Android

android/app/src/main/kotlin/.../MainActivity.kt(或者Java文件)中创建Tor管理代码:

package com.example.tor_flutter_app

import android.os.Bundle
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

class MainActivity: FlutterActivity() {
    private val CHANNEL = "com.example.tor_flutter_app/tor"

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
            if (call.method == "startTor") {
                startTor { success ->
                    result.success(success)
                }
            } else if (call.method == "stopTor") {
                stopTor { success ->
                    result.success(success)
                }
            } else {
                result.notImplemented()
            }
        }
    }

    private fun startTor(completion: (Boolean) -> Unit) {
        // 启动Tor的代码
        completion(true) // 假设启动成功
    }

    private fun stopTor(completion: (Boolean) -> Unit) {
        // 停止Tor的代码
        completion(true) // 假设停止成功
    }
}

4. Flutter代码调用

在Flutter代码中,你可以通过MethodChannel调用原生方法:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  static const platform = MethodChannel('com.example.tor_flutter_app/tor');

  Future<void> _startTor() async {
    try {
      bool success = await platform.invokeMethod('startTor');
      print('Tor started: $success');
    } on PlatformException catch (e) {
      print("Failed to start Tor: '${e.message}'.");
    }
  }

  Future<void> _stopTor() async {
    try {
      bool success = await platform.invokeMethod('stopTor');
      print('Tor stopped: $success');
    } on PlatformException catch (e) {
      print("Failed to stop Tor: '${e.message}'.");
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Tor Flutter App'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              ElevatedButton(
                onPressed: _startTor,
                child: Text('Start Tor'),
              ),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: _stopTor,
                child: Text('Stop Tor'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

注意事项

  1. Tor的集成:Tor的集成在iOS和Android上都比较复杂,需要处理很多细节,比如配置Tor的控制端口、处理启动和停止的逻辑、错误处理等。
  2. 安全性:确保Tor配置正确,避免泄露用户信息。
  3. 性能:Tor会增加网络延迟,因此需要考虑应用性能的影响。
  4. 法律合规:在某些地区使用Tor可能受到法律限制,确保你的应用符合当地法律法规。

这个示例仅展示了基本的集成方法,实际应用中需要根据具体需求进行更多的定制和优化。

回到顶部