凌峰创科服务平台

Android如何搭建FTP服务器?

核心原理

一个 FTP 服务器在 Android 上的工作流程如下:

Android如何搭建FTP服务器?-图1
(图片来源网络,侵删)
  1. 启动服务:你的 Android App 启动一个后台服务,这个服务会持续监听网络上的 FTP 请求。
  2. 创建服务器实例:服务内部使用一个 FTP 服务器库(如 NanoFTPdApache FTPServer)来创建一个服务器实例。
  3. 绑定端口:服务器实例会绑定到一个指定的网络端口(通常是 21)。
  4. 处理请求:当网络上的另一台设备(客户端)尝试连接这个 IP 地址和端口时,服务器库会接收并处理这些 FTP 命令(如 USER, PASS, LIST, RETR 等)。
  5. 访问文件:服务器库通过 Android 的文件系统 API 来读取、写入、列出或删除你 App 沙盒目录或共享存储(SD卡)中的文件。
  6. 返回响应:服务器将操作结果(成功、失败、文件列表、文件内容等)返回给客户端。

关键点

  • 权限:App 需要网络访问权限,以及读取/写入外部存储的权限。
  • IP 地址:你需要知道你手机的局域网 IP 地址,客户端才能连接,通常在 Wi-Fi 设置中可以找到。
  • 安全性:默认的 FTP 是不加密的,所有数据(包括用户名和密码)都以明文传输,在公网或对安全性要求高的环境中,应考虑使用 FTPS (FTP over SSL/TLS)SFTP (SSH File Transfer Protocol),对于本地局域网使用,普通 FTP 通常足够。

推荐库选择

虽然你可以自己用 Socket 编写一个 FTP 服务器,但这非常复杂且容易出错,强烈建议使用成熟的第三方库。

  1. NanoFTPd (推荐)

    • 优点:轻量级、专门为 Android 设计、API 简单、支持 FTP 和 FTPS,它被许多知名 App(如 Solid Explorer)使用,非常稳定。
    • 缺点:文档相对较少,但代码示例清晰。
    • GitHub 地址https://github.com/iNPUTmice/NanoFTPd
  2. Apache FTPServer

    Android如何搭建FTP服务器?-图2
    (图片来源网络,侵删)
    • 优点:功能非常强大、稳定、历史悠久,是一个成熟的 FTP 服务器框架。
    • 缺点:相对较重,集成和配置可能比 NanoFTPd 稍微复杂一些。
    • GitHub 地址https://github.com/apache/ftpserver

本教程将以 NanoFTPd 为例,因为它更简单直接,非常适合快速上手。


详细搭建步骤 (使用 NanoFTPd)

步骤 1:在 Android Studio 中创建新项目

  1. 打开 Android Studio,创建一个新的 Empty Activity 项目。
  2. 选择你喜欢的语言 (Kotlin/Java) 和最低 SDK 版本。

步骤 2:添加依赖

打开你的 app/build.gradle.kts (或 build.gradle) 文件,在 dependencies 代码块中添加 NanoFTPd 的依赖。

// build.gradle (Groovy)
dependencies {
    // ... 其他依赖
    implementation 'com.github.iNPUTmice:NanoFTPd:1.0.0' // 请检查 GitHub 获取最新版本
}
// build.gradle.kts (Kotlin)
dependencies {
    // ... 其他依赖
    implementation("com.github.iNPUTmice:NanoFTPd:1.0.0") // 请检查 GitHub 获取最新版本
}

点击 "Sync Now" 同步项目。

步骤 3:添加网络和存储权限

打开 app/src/main/AndroidManifest.xml 文件,添加以下权限。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <!-- 网络权限 -->
    <uses-permission android:name="android.permission.INTERNET" />
    <!-- 读取外部存储权限 (Android 13+ 需要 READ_MEDIA_IMAGES, READ_MEDIA_VIDEO, READ_MEDIA_AUDIO) -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <!-- 写入外部存储权限 (Android 13+ 需要 MANAGE_EXTERNAL_STORAGE 或特定媒体权限) -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <!-- Android 13+ 需要请求通知权限来显示服务器状态 -->
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
    <application
        ... >
        <activity ...>
            ...
        </activity>
        <!-- 声明一个 Service,用于在后台运行 FTP 服务器 -->
        <service
            android:name=".FtpServerService"
            android:enabled="true"
            android:exported="false" />
    </application>
</manifest>

权限说明

  • 对于 Android 13 (API 33) 及以上,READ_EXTERNAL_STORAGE 被拆分为 READ_MEDIA_IMAGES 等权限,如果你的服务器需要访问所有文件,MANAGE_EXTERNAL_STORAGE 是最简单的,但需要用户手动在设置中授权,且有严格限制,对于演示,可以先用 READ_EXTERNAL_STORAGE 并在运行时请求。
  • WRITE_EXTERNAL_STORAGE 同样受版本影响。

步骤 4:创建 FTP 服务器服务

创建一个新的 Kotlin/Java 类 FtpServerService.kt,继承自 Service

// FtpServerService.kt
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.Intent
import android.os.Build
import android.os.IBinder
import android.util.Log
import com.github.pedrovgs.lynx.LynxConfig
import com.github.pedrovgs.lynx.LynxService
import java.io.File
class FtpServerService : Service() {
    private lateinit var ftpServer: NanoFtpd
    private val TAG = "FtpServerService"
    private val NOTIFICATION_CHANNEL_ID = "FtpServerChannel"
    override fun onCreate() {
        super.onCreate()
        createNotificationChannel()
        startForeground(1, createNotification())
        startFtpServer()
    }
    override fun onBind(intent: Intent): IBinder? {
        return null // 我们不提供绑定
    }
    override fun onDestroy() {
        super.onDestroy()
        Log.d(TAG, "Stopping FTP server...")
        ftpServer.stop()
    }
    private fun startFtpServer() {
        try {
            // 1. 设置根目录,这里使用外部存储的根目录。
            // 注意:你需要确保应用有权限访问这个目录。
            val rootDir = File(getExternalFilesDir(null)?.absolutePath ?: "/sdcard/ftp_root")
            if (!rootDir.exists()) {
                rootDir.mkdirs()
            }
            Log.d(TAG, "FTP Root Directory: ${rootDir.absolutePath}")
            // 2. 创建服务器配置
            val config = NanoFtpdConfig.Builder()
                .port(2121) // 使用非标准端口避免冲突,也可以用 21
                .rootDirectory(rootDir)
                .anonymousEnabled(false) // 禁用匿名登录
                .user("user") // 用户名
                .password("password") // 密码
                .build()
            // 3. 创建 NanoFtpd 实例
            ftpServer = NanoFtpd(config)
            // 4. 启动服务器
            ftpServer.start()
            Log.d(TAG, "FTP server started on port ${config.port}")
        } catch (e: Exception) {
            Log.e(TAG, "Failed to start FTP server", e)
        }
    }
    private fun createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val serviceChannel = NotificationChannel(
                NOTIFICATION_CHANNEL_ID,
                "FTP Server Service",
                NotificationManager.IMPORTANCE_DEFAULT
            )
            val manager = getSystemService(NotificationManager::class.java)
            manager.createNotificationChannel(serviceChannel)
        }
    }
    private fun createNotification(): Notification {
        return Notification.Builder(this, NOTIFICATION_CHANNEL_ID)
            .setContentTitle("FTP Server")
            .setContentText("Server is running. Check logs for IP address.")
            .setSmallIcon(android.R.drawable.ic_dialog_info)
            .build()
    }
}

步骤 5:启动和管理服务

你可以在一个 Activity 中通过按钮来启动和停止这个服务。

// MainActivity.kt
import android.content.Intent
import android.os.Bundle
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val startButton: Button = findViewById(R.id.start_button)
        val stopButton: Button = findViewById(R.id.stop_button)
        startButton.setOnClickListener {
            // 启动 FTP 服务器服务
            val serviceIntent = Intent(this, FtpServerService::class.java)
            startService(serviceIntent)
            startButton.isEnabled = false
            stopButton.isEnabled = true
        }
        stopButton.setOnClickListener {
            // 停止 FTP 服务器服务
            val serviceIntent = Intent(this, FtpServerService::class.java)
            stopService(serviceIntent)
            startButton.isEnabled = true
            stopButton.isEnabled = false
        }
    }
}

步骤 6:运行并获取 IP 地址

  1. 将你的手机和电脑连接到同一个 Wi-Fi 网络
  2. 在 Android Studio 中运行你的 App。
  3. 点击 "Start" 按钮。
  4. 打开手机的 Wi-Fi 设置,找到当前连接的网络的 IP 地址,它通常是一个以 168.x.x0.x.x 开头的地址。
    • 路径设置 -> WLAN -> 当前网络 -> IP 地址
  5. 你可以在 Logcat 中搜索 FtpServerService,应该能看到类似 "FTP server started on port 2121" 和 "FTP Root Directory: ..." 的日志。

如何连接和使用

你可以从任何 FTP 客户端连接到你的手机了。

从 Windows 连接

  1. 在 Windows 的文件资源管理器地址栏中,输入 ftp://你的手机IP地址:端口号
    • ftp://192.168.1.105:2121
  2. 系统会提示输入用户名和密码。
    • 用户名user
    • 密码password
  3. 连接成功后,你就可以像操作普通文件夹一样,拖放或复制文件了。

从 macOS 连接

  1. 打开 "访达" (Finder)。
  2. 点击菜单栏的 "前往" -> "连接服务器" (或使用快捷键 Cmd + K)。
  3. 在服务器地址栏输入 ftp://你的手机IP地址:端口号,然后点击 "连接"。
  4. 输入用户名和密码。

从手机连接 (使用 File Manager App)

  1. 在你的另一台手机上安装一个支持 FTP 的文件管理器(如 Solid Explorer, X-plore 等)。
  2. 打开该 App,找到 "网络" 或 "LAN" 功能。
  3. 添加一个新的 FTP 服务器,填入你的手机 IP 地址、端口、用户名和密码。
  4. 连接后即可访问和传输文件。

重要注意事项和进阶

  1. 权限问题

    • Android 13+:上面的 READ_EXTERNAL_STORAGE 在 Android 13 上可能不够用,如果你遇到 "权限拒绝" 错误,请确保你已经在运行时正确请求了所有必要的权限,对于完全访问,可能需要引导用户去 设置 -> 应用 -> [你的App] -> 权限 -> 所有文件访问权限 中手动开启 MANAGE_EXTERNAL_STORAGE
    • 作用域存储:现代 Android 推荐使用作用域存储,如果你的 FTP 服务器只需要访问特定类型的文件(如图片),可以考虑使用 MediaStore API 来访问,而不是直接访问文件路径。
  2. 安全性

    • 不要在公网上开放:普通 FTP 极不安全,仅限在可信的局域网内使用。
    • 使用强密码:设置一个复杂的密码。
    • 考虑 FTPS:如果需要更高安全性,可以研究 NanoFtpd 的 FTPS 配置,这需要配置 SSL/TLS 证书,过程会更复杂。
  3. 电池和性能

    • FTP 服务器是一个持续运行的服务,会消耗一定的电量,当你不需要时,务必通过 App 停止服务。
    • 对于大文件传输,确保你的手机有足够的性能和稳定的网络连接。
  4. 文件共享根目录

    • 示例代码中,FTP 的根目录是 App.getExternalFilesDir(null),这个目录是 App 私有的,其他 App 无法直接访问,但通过 FTP 服务暴露给了网络。
    • 如果你希望共享的是 SD 卡的公共目录(如 Download),路径应该是 Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),但这样需要更高级的权限管理。

通过以上步骤,你就可以成功地在你的 Android 设备上搭建一个功能完备的 FTP 服务器了。

分享:
扫描分享到社交APP
上一篇
下一篇