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
相关产品推荐
相关产品推荐

