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

Android Studio(Java)实现APP内PDF下载及登录用户专属查看

Android(Java)实现登录用户专属内部PDF下载与查看方案

一、登录状态校验前置

所有涉及PDF下载、查看的操作,必须先校验用户登录状态:

  • 用SharedPreferences持久化存储登录状态(如isLoggedIn)和用户Token,每次进入PDF相关页面或触发下载前先读取校验:
// 读取登录状态示例
SharedPreferences sp = getSharedPreferences("UserPrefs", MODE_PRIVATE);
boolean isLoggedIn = sp.getBoolean("isLoggedIn", false);
String authToken = sp.getString("authToken", "");

if (!isLoggedIn || TextUtils.isEmpty(authToken)) {
    // 跳转登录页面,终止当前操作
    startActivity(new Intent(this, LoginActivity.class));
    finish();
    return;
}
  • 服务器端接口层面:PDF下载接口必须要求携带有效Token,服务器验证Token合法性后才返回文件流,避免未登录用户直接请求下载链接。

二、PDF安全下载到APP内部存储

将PDF下载到APP专属内部存储目录,该目录默认只有当前APP可访问(无需申请外部存储权限),防止其他APP或用户直接获取文件:

  • 选择内部存储目录:用getFilesDir()(持久化存储,卸载APP才删除)或getCacheDir()(临时存储,系统可能清理),示例用getFilesDir():
// 获取内部存储目录
File internalDir = getFilesDir();
File pdfDir = new File(internalDir, "private_pdfs");
if (!pdfDir.exists()) {
    pdfDir.mkdirs(); // 创建子目录
}
File targetPdf = new File(pdfDir, "document_" + System.currentTimeMillis() + ".pdf");
  • 用OkHttp下载PDF(需添加OkHttp依赖到build.gradle):
// 构建请求,携带登录Token
Request request = new Request.Builder()
        .url("你的PDF下载接口地址")
        .addHeader("Authorization", "Bearer " + authToken)
        .build();

OkHttpClient client = new OkHttpClient();
client.newCall(request).enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        // 处理下载失败
        runOnUiThread(() -> Toast.makeText(MainActivity.this, "下载失败", Toast.LENGTH_SHORT).show());
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        if (response.isSuccessful() && response.body() != null) {
            // 将响应体写入内部存储文件
            InputStream inputStream = response.body().byteStream();
            FileOutputStream outputStream = new FileOutputStream(targetPdf);
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
            outputStream.flush();
            outputStream.close();
            inputStream.close();

            runOnUiThread(() -> {
                Toast.makeText(MainActivity.this, "下载完成", Toast.LENGTH_SHORT).show();
                // 跳转到PDF查看页面,传递文件路径
                Intent intent = new Intent(MainActivity.this, PdfViewerActivity.class);
                intent.putExtra("PDF_PATH", targetPdf.getAbsolutePath());
                startActivity(intent);
            });
        } else {
            runOnUiThread(() -> Toast.makeText(MainActivity.this, "无权限下载", Toast.LENGTH_SHORT).show());
        }
    }
});

三、内部PDF专属查看实现

不能调用第三方APP打开PDF,必须在APP内集成PDF渲染组件,确保文件不流出:

  • 集成AndroidPdfViewer库(添加依赖到build.gradle:implementation 'com.github.barteksc:android-pdf-viewer:3.2.0-beta.1')
  • 在PdfViewerActivity的布局中添加PDFView:
<com.github.barteksc.pdfviewer.PDFView
    android:id="@+id/pdfView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
  • 在PdfViewerActivity中校验登录状态并加载PDF:
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_pdf_viewer);

    // 再次校验登录状态
    SharedPreferences sp = getSharedPreferences("UserPrefs", MODE_PRIVATE);
    boolean isLoggedIn = sp.getBoolean("isLoggedIn", false);
    if (!isLoggedIn) {
        startActivity(new Intent(this, LoginActivity.class));
        finish();
        return;
    }

    String pdfPath = getIntent().getStringExtra("PDF_PATH");
    PDFView pdfView = findViewById(R.id.pdfView);
    pdfView.fromFile(new File(pdfPath))
            .defaultPage(0)
            .enableSwipe(true)
            .swipeHorizontal(false)
            .enableDoubletap(true)
            .load();
}

四、增强安全措施(可选)

  • 文件加密:下载完成后对PDF文件进行AES加密,查看时解密后加载,即使设备root也无法直接读取原始文件:
// 简单AES加密示例(需自行完善密钥管理,密钥应安全存储,避免硬编码)
public static void encryptFile(File inputFile, File outputFile, String key) throws Exception {
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "AES");
    IvParameterSpec iv = new IvParameterSpec(new byte[16]);
    cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);

    FileInputStream inputStream = new FileInputStream(inputFile);
    FileOutputStream outputStream = new FileOutputStream(outputFile);
    CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, cipher);

    byte[] buffer = new byte[4096];
    int bytesRead;
    while ((bytesRead = inputStream.read(buffer)) != -1) {
        cipherOutputStream.write(buffer, 0, bytesRead);
    }
    inputStream.close();
    cipherOutputStream.close();
}
  • 禁止截图/录屏:在PDF查看页面添加防截图设置,防止用户通过截图泄露内容:
@Override
protected void onResume() {
    super.onResume();
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
}

@Override
protected void onPause() {
    super.onPause();
    getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
}

内容的提问来源于stack exchange,提问作者Subham Roy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 23:30:16