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

如何在Firebase中向特定用户发送PDF并仅允许该用户查看?

实现向Firebase特定用户发送私有PDF及数据的方案

需求核心

  • 上传的数据/PDF仅目标指定用户可见
  • 需通过用户UID定向发送内容
  • 确保数据安全,非目标用户无法访问

步骤1:界面调整

在activity_uploadfile.xml中添加输入框,用于填写目标用户的UID:

<EditText
    android:id="@+id/targetUserId"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="输入目标用户UID"
    android:inputType="text" />

步骤2:核心代码修改

修正原代码空指针问题,添加目标UID校验,调整数据存储路径以绑定目标用户:

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import android.Manifest;
import android.app.ProgressDialog;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Toast;

import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.storage.FirebaseStorage;
import com.google.firebase.storage.OnProgressListener;
import com.google.firebase.storage.StorageReference;
import com.google.firebase.storage.UploadTask;
import com.karumi.dexter.Dexter;
import com.karumi.dexter.PermissionToken;
import com.karumi.dexter.listener.PermissionDeniedResponse;
import com.karumi.dexter.listener.PermissionGrantedResponse;
import com.karumi.dexter.listener.PermissionRequest;
import com.karumi.dexter.listener.single.PermissionListener;

public class uploadfile extends AppCompatActivity {

    ImageView imagebrowse, imageupload, filelogo, cancelfile;
    Uri filepath;
    EditText filetitle, targetUserId; // 新增目标UID输入框

    StorageReference storageReference;
    DatabaseReference databaseReference;
    private FirebaseAuth firebaseAuth;
    String currentUid;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_uploadfile);

        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

        // 先初始化FirebaseAuth,避免空指针
        firebaseAuth = FirebaseAuth.getInstance();
        FirebaseUser user = firebaseAuth.getCurrentUser();
        if (user != null) {
            currentUid = user.getUid();
        } else {
            Toast.makeText(this, "请先登录", Toast.LENGTH_SHORT).show();
            finish();
            return;
        }

        storageReference = FirebaseStorage.getInstance().getReference();
        databaseReference = FirebaseDatabase.getInstance().getReference("user_files"); // 调整根节点名称,区分用户专属文件

        filetitle = findViewById(R.id.filetitle);
        targetUserId = findViewById(R.id.targetUserId); // 初始化目标UID输入框

        imagebrowse = findViewById(R.id.imagebrowse);
        imageupload = findViewById(R.id.imageupload);

        filelogo = findViewById(R.id.filelogo);
        cancelfile = findViewById(R.id.cancelfile);

        filelogo.setVisibility(View.INVISIBLE);
        cancelfile.setVisibility(View.INVISIBLE);

        cancelfile.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                filelogo.setVisibility(View.INVISIBLE);
                cancelfile.setVisibility(View.INVISIBLE);
                imagebrowse.setVisibility(View.VISIBLE);
            }
        });

        imagebrowse.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Dexter.withContext(getApplicationContext())
                        .withPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
                        .withListener(new PermissionListener() {
                            @Override
                            public void onPermissionGranted(PermissionGrantedResponse permissionGrantedResponse) {
                                Intent intent = new Intent();
                                intent.setType("application/pdf");
                                intent.setAction(Intent.ACTION_GET_CONTENT);
                                startActivityForResult(Intent.createChooser(intent, "Select Pdf Files"), 101);
                            }

                            @Override
                            public void onPermissionDenied(PermissionDeniedResponse permissionDeniedResponse) {
                                Toast.makeText(uploadfile.this, "需要存储权限才能选择文件", Toast.LENGTH_SHORT).show();
                            }

                            @Override
                            public void onPermissionRationaleShouldBeShown(PermissionRequest permissionRequest, PermissionToken permissionToken) {
                                permissionToken.continuePermissionRequest();
                            }
                        }).check();
            }
        });

        imageupload.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (filepath == null) {
                    Toast.makeText(uploadfile.this, "请先选择PDF文件", Toast.LENGTH_SHORT).show();
                    return;
                }
                String targetId = targetUserId.getText().toString().trim();
                if (targetId.isEmpty()) {
                    Toast.makeText(uploadfile.this, "请输入目标用户UID", Toast.LENGTH_SHORT).show();
                    return;
                }
                processupload(filepath, targetId); // 传入目标UID
            }
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == 101 && resultCode == RESULT_OK && data != null) {
            filepath = data.getData();
            filelogo.setVisibility(View.VISIBLE);
            cancelfile.setVisibility(View.VISIBLE);
            imagebrowse.setVisibility(View.INVISIBLE);
        }
    }

    public void processupload(Uri filepath, String targetId) {
        final ProgressDialog pd = new ProgressDialog(this);
        pd.setTitle("File Uploading....!!!");
        pd.show();

        // 存储路径绑定目标用户,方便权限控制
        final StorageReference reference = storageReference.child("user_pdfs/" + targetId + "/" + System.currentTimeMillis() + ".pdf");
        reference.putFile(filepath)
                .addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
                    @Override
                    public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
                        reference.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
                            @Override
                            public void onSuccess(Uri uri) {
                                // 将文件信息存入目标用户的专属节点
                                model obj = new model(filetitle.getText().toString(), uri.toString(), currentUid, targetId, System.currentTimeMillis());
                                databaseReference.child(targetId).child(databaseReference.push().getKey()).setValue(obj);

                                pd.dismiss();
                                Toast.makeText(getApplicationContext(), "文件已发送给目标用户", Toast.LENGTH_LONG).show();

                                // 重置界面状态
                                filelogo.setVisibility(View.INVISIBLE);
                                cancelfile.setVisibility(View.INVISIBLE);
                                imagebrowse.setVisibility(View.VISIBLE);
                                filetitle.setText("");
                                targetUserId.setText("");
                            }
                        });
                    }
                })
                .addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
                    @Override
                    public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
                        float percent = (100 * taskSnapshot.getBytesTransferred()) / taskSnapshot.getTotalByteCount();
                        pd.setMessage("Uploaded :" + (int) percent + "%");
                    }
                });
    }
}

关键修改点:

  1. 修复空指针:调整FirebaseAuth初始化顺序,先初始化再获取当前用户
  2. 新增目标UID输入:添加输入框并在上传前校验是否填写
  3. 绑定用户存储路径:
    • Storage中PDF存入user_pdfs/{目标UID}/目录
    • 数据库文件信息存入user_files/{目标UID}/节点,确保数据和目标用户绑定
  4. 扩展model字段:新增发送者ID、接收者ID、上传时间,方便后续管理

步骤3:Firebase安全规则配置

这是确保数据私有性的核心,必须配置规则限制非目标用户访问:

Realtime Database规则:

{
  "rules": {
    "user_files": {
      "$targetUid": {
        ".read": "auth != null && auth.uid == $targetUid",
        ".write": "auth != null" // 允许所有已登录用户发送,可按需限制为特定角色
      }
    }
  }
}

Storage规则:

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /user_pdfs/{targetUid}/{allPaths=**} {
      allow read: if auth != null && auth.uid == targetUid;
      allow write: if auth != null;
    }
  }
}

规则说明:

  • 仅目标用户自身可读取属于自己的文件数据和PDF
  • 所有已登录用户可发送数据,若需更严格权限可添加额外校验(如仅好友可发送)

目标用户查看数据示例

目标用户登录后,查询自身专属节点即可获取所有发送给自己的文件:

DatabaseReference userFilesRef = FirebaseDatabase.getInstance().getReference("user_files").child(currentUser.getUid());
userFilesRef.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot snapshot) {
        List<model> fileList = new ArrayList<>();
        for (DataSnapshot ds : snapshot.getChildren()) {
            model file = ds.getValue(model.class);
            fileList.add(file);
        }
        // 用RecyclerView展示文件列表,点击可通过URL打开PDF
    }

    @Override
    public void onCancelled(@NonNull DatabaseError error) {
        Toast.makeText(context, "加载失败", Toast.LENGTH_SHORT).show();
    }
});

内容的提问来源于stack exchange,提问作者Jimuel Destura

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 12:26:00