在移动应用开发和测试过程中,经常需要从本地服务器获取最新的 APK 安装包。本文将详细介绍如何使用 Java 构建一个能够搜索本地最新 APK 文件并通过 HTTP 请求提供下载服务的应用。
功能概述
- 递归搜索本地目录,查找所有 APK 文件
- 根据文件修改时间找出最新的 APK 文件
- 通过 HTTP 请求响应机制,将 APK 文件返回给前端
- 处理各种异常情况,确保服务稳定可靠
实现本地 APK 文件搜索
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class ApkFileFinder {
private static final String APK_EXTENSION = ".apk";
/**
* 查找指定目录下最新的APK文件
* @param searchDir 搜索目录
* @return 最新APK文件的Path,未找到时返回null
* @throws IOException 文件操作异常
*/
public static Path findLatestApk(String searchDir) throws IOException {
try (Stream<Path> walk = Files.walk(Paths.get(searchDir))) {
List<Path> apkFiles = walk
.filter(Files::isRegularFile)
.filter(p -> p.getFileName().toString().toLowerCase().endsWith(APK_EXTENSION))
.collect(Collectors.toList());
if (apkFiles.isEmpty()) {
return null;
}
return apkFiles.stream()
.max(Comparator.comparingLong(p -> {
try {
return Files.getLastModifiedTime(p).toMillis();
} catch (IOException e) {
return 0;
}
}))
.orElse(null);
}
}
}
创建 HTTP 下载服务
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/downloadLatestApk")
public class ApkDownloadServlet extends HttpServlet {
private static final String APK_SEARCH_DIR = "C:/apps/";
private static final String DEFAULT_CHARSET = "UTF-8";
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
// 设置响应编码
resp.setCharacterEncoding(DEFAULT_CHARSET);
// 查找最新APK
Path latestApk = ApkFileFinder.findLatestApk(APK_SEARCH_DIR);
if (latestApk == null) {
resp.sendError(HttpServletResponse.SC_NOT_FOUND, "未找到APK文件");
return;
}
// 设置响应头
String fileName = generateDownloadFileName(latestApk);
resp.setContentType("application/vnd.android.package-archive");
resp.setHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(fileName, DEFAULT_CHARSET) + "\"");
resp.setHeader("Content-Length", String.valueOf(Files.size(latestApk)));
// 输出文件内容
Files.copy(latestApk, resp.getOutputStream());
} catch (Exception e) {
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "下载过程中发生错误: " + e.getMessage());
}
}
private String generateDownloadFileName(Path sourcePath) {
String baseName = sourcePath.getFileName().toString();
int extIndex = baseName.lastIndexOf('.');
String nameWithoutExt = extIndex > 0 ? baseName.substring(0, extIndex) : baseName;
String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
return nameWithoutExt + "_" + timestamp + ".apk";
}
}
部署与使用
1. 环境准备
- JDK 8 或更高版本
- Apache Tomcat 或其他 Servlet 容器
- Maven(可选,用于项目构建)
2. 创建 Web 项目
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
3. 部署应用
4. 配置搜索路径
5. 访问服务
http://localhost:8080/your-context-root/downloadLatestApk
示例与测试
C:/apps/
├── app-v1.0.apk (修改时间: 2023-01-01 10:00)
├── app-v1.1.apk (修改时间: 2023-01-10 14:30)
└── app-v1.2.apk (修改时间: 2023-01-15 09:15)
常见问题与解决方案
- 检查 APK_SEARCH_DIR 路径是否正确
- 确保 Tomcat 用户有访问该目录的权限
- 确认代码中使用了 URLEncoder 处理文件名
- 确保 Servlet 容器配置为使用 UTF-8 编码
- 对于非常大的 APK 文件,考虑使用缓冲流或异步下载