You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Android DownloadManager支持NTLM认证以下载校园网文件?

嗨,这个问题我之前帮朋友解决过!Android自带的DownloadManager确实有个硬伤——它原生完全不支持NTLM或者Negotiate这种校园网常用的域认证方式,只认Basic、Digest这类简单的HTTP基础认证。所以你直接改DownloadManager.Request是没用的,得换个思路,自己实现带NTLM认证的下载逻辑,我给你两个靠谱的方案:


方案一:用OkHttp实现(推荐,配置简单还灵活)

OkHttp这个第三方库内置了对NTLM认证的支持,而且还能轻松模拟DownloadManager的通知栏进度提示,步骤也不复杂:

第一步:先加依赖

在你项目的Module级build.gradle里添加上OkHttp的依赖(版本可以用最新的,我这里给的是稳定版):

implementation 'com.squareup.okhttp3:okhttp:4.12.0'

第二步:写下载工具类

我给你写了个完整的工具类,包含NTLM认证配置、文件保存、通知栏进度更新,直接复制就能用:

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Build;
import android.os.Environment;
import androidx.core.app.NotificationCompat;
import okhttp3.Authenticator;
import okhttp3.Credentials;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.Route;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class NTLMDownloader {
    private Context mContext;
    private NotificationManager mNotificationManager;
    private NotificationCompat.Builder mNotificationBuilder;
    private static final int NOTIFICATION_ID = 1001;
    private static final String CHANNEL_ID = "ntlm_download_channel";

    public NTLMDownloader(Context context) {
        mContext = context;
        createNotificationChannel();
    }

    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                    CHANNEL_ID,
                    "下载通知",
                    NotificationManager.IMPORTANCE_DEFAULT
            );
            mNotificationManager = mContext.getSystemService(NotificationManager.class);
            mNotificationManager.createNotificationChannel(channel);
        } else {
            mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
        }
    }

    public void startDownload(String url, String username, String password, String domain) {
        // 配置OkHttpClient的NTLM认证,这里要注意凭证格式是domain\\username
        OkHttpClient client = new OkHttpClient.Builder()
                .authenticator(new Authenticator() {
                    @Override
                    public Request authenticate(Route route, Response response) throws IOException {
                        String credential = Credentials.ntlm(username, password, domain);
                        return response.request().newBuilder()
                                .header("Authorization", credential)
                                .build();
                    }
                })
                .build();

        Request request = new Request.Builder()
                .url(url)
                .build();

        // 下载要放子线程,别卡主线程
        new Thread(() -> {
            try (Response response = client.newCall(request).execute()) {
                if (!response.isSuccessful()) {
                    throw new IOException("请求失败: " + response.code());
                }

                // 把文件存到系统Downloads目录,你也可以改其他路径
                File downloadDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
                String fileName = url.substring(url.lastIndexOf("/") + 1);
                File file = new File(downloadDir, fileName);

                try (InputStream inputStream = response.body().byteStream();
                     OutputStream outputStream = new FileOutputStream(file)) {

                    byte[] buffer = new byte[4096];
                    long totalBytes = response.body().contentLength();
                    long downloadedBytes = 0;
                    int bytesRead;

                    // 初始化通知栏
                    mNotificationBuilder = new NotificationCompat.Builder(mContext, CHANNEL_ID)
                            .setSmallIcon(android.R.drawable.stat_sys_download)
                            .setContentTitle("正在下载")
                            .setContentText(fileName)
                            .setProgress((int) totalBytes, 0, false)
                            .setOngoing(true);
                    mNotificationManager.notify(NOTIFICATION_ID, mNotificationBuilder.build());

                    // 边读边写,更新进度
                    while ((bytesRead = inputStream.read(buffer)) != -1) {
                        outputStream.write(buffer, 0, bytesRead);
                        downloadedBytes += bytesRead;

                        mNotificationBuilder.setProgress((int) totalBytes, (int) downloadedBytes, false);
                        mNotificationManager.notify(NOTIFICATION_ID, mNotificationBuilder.build());
                    }

                    // 下载完成更新通知
                    mNotificationBuilder.setContentTitle("下载完成")
                            .setProgress(0, 0, false)
                            .setOngoing(false);
                    mNotificationManager.notify(NOTIFICATION_ID, mNotificationBuilder.build());

                } catch (IOException e) {
                    e.printStackTrace();
                    // 下载失败提示
                    mNotificationBuilder.setContentTitle("下载失败")
                            .setProgress(0, 0, false)
                            .setOngoing(false);
                    mNotificationManager.notify(NOTIFICATION_ID, mNotificationBuilder.build());
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

第三步:调用下载

在你的Activity或者Fragment里,直接实例化这个工具类调用就行:

// 替换成你的校园网文件URL、用户名、密码,域如果没有的话传空字符串就行
NTLMDownloader downloader = new NTLMDownloader(this);
downloader.startDownload("https://你的校园网文件地址", "学号/用户名", "密码", "校园网域");

方案二:用原生HttpURLConnection实现(不用第三方库)

如果你不想加第三方依赖,也可以用Android原生的HttpURLConnection,它也支持NTLM,不过是全局配置,可能会影响其他请求:

// 全局设置NTLM认证,注意这里的用户名格式是"域\\用户名"
Authenticator.setDefault(new Authenticator() {
    @Override
    protected PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication(
                "校园网域\\用户名",
                "密码".toCharArray()
        );
    }
});

// 然后就是常规的HttpURLConnection下载逻辑,和普通下载一样
// 这里就不写完整代码了,核心就是设置完认证后,正常发起请求、读写文件就行

⚠️ 注意:这个全局认证会影响整个App的所有HTTP请求,如果你的App还有其他不需要NTLM认证的接口,可能会出问题,所以还是推荐用OkHttp的局部配置更稳妥。


为啥DownloadManager搞不定?

说句实在的,DownloadManager是系统级的服务,它的认证逻辑是写死在系统源码里的,只支持Basic和Digest,完全没做NTLM/Negotiate的适配,所以不管怎么改DownloadManager.Request都没用,只能绕开它自己实现。

内容的提问来源于stack exchange,提问作者Ahmed Ali

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:32:03