将文件上传到 Firebase 后如何获取文件 URL?

Posted

技术标签:

【中文标题】将文件上传到 Firebase 后如何获取文件 URL?【英文标题】:How to get file URL after uploading them to Firebase? 【发布时间】:2017-09-24 07:31:47 【问题描述】:

将文件上传到 Firebase 后,如何获取它的 URL 以便将其存储起来以备后用?我想将 URL 写入 Firebase 数据库,以便其他用户可以访问该图像。

我正在像这样上传文件:

public void uploadFile()


    StorageReference filepath = mstorageRef.child("folder").child(filename);

    Uri File= Uri.fromFile(new File(mFileName));

    filepath.putFile(File).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() 
        @Override
        public void onSuccess(UploadTask.TaskSnapshot taskSnapshot)
        
            Toast.makeText(MtActivity.this, "Upload Done", Toast.LENGTH_LONG).show();
        
    );

我已经确认文件实际上正在上传,所以现在我只需要可以写入数据库的 URL。但是,当我尝试这样做时:

Uri downloadUrl = taskSnapshot.getMetadata().getDownloadUrl();

它给了我一个错误并说This method should only be accessed from tests or within private scope

我不确定这意味着什么,我也不知道为什么会收到该错误,因为我关注的是 Firebase 提供的 this example。

有没有获取 URL 的新方法?

另外,该 URL 是不是该项目特有的?这意味着如果我将它存储到数据库中并稍后尝试访问它,我可以这样做吗?

【问题讨论】:

你应该写taskSnapshot.getDownloadUrl(),而不是taskSnapshot.getMetadata().getDownloadUrl() @AnggrayudiH 我试过了,它给了我同样的错误信息。出于某种原因,它不允许我在 addOnSuccessListener() 方法中调用该方法。 关于你看到的错误,你看到this post了吗? 检查这个解决方案***.com/questions/50158921/… 它对我有用。 【参考方案1】:

你试过taskSnapshot.getDownloadUrl()吗? 如果这也不起作用,您可以通过 mstorageRef.child("folder").child(filename).toString() 获取成功侦听器中的图像位置

【讨论】:

我试过taskSnapshot.getDownloadUrl(),但它给出了同样的错误。另外,我将如何使用您向我展示的其他方法?另外,另一种方法对我有什么作用?我该如何取回文件? Url 只不过是存储图像的 firebase 路径,因此在上传成功后,您应该知道正在存储上创建路径,因此请使用您保存的相同存储引用并将其设置为 String 。 .in 你的代码filepath.toString() 这是有道理的。但是,如果我在另一个活动中并且想要访问该图像,我该怎么做呢?由于我无权访问mstorageRef,我将如何访问图像? 在我的工作中,图像总是与对象数据相关联,因此将图像 url 与对象数据一起存储在 mDatabase 中,然后从任何活动中检索图像在数据库中的路径 没错!如果我有 URL,那么我可以访问该图像,但我如何获得它?如果我使用mstorageRef.child("folder").child(filename).toString(),我将获得存储位置,而不是 HTTP URL。【参考方案2】:

试试这个:

final Uri uri = data.getData();

StorageReference filepath = mStorageRef.child("folder").child(filename);
filepath.putFile(uri).addOnSuccessListener(new 

OnSuccessListener<UploadTask.TaskSnapshot>() 

        @Override
        public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) 

            Uri downloadUri = taskSnapshot.getDownloadUrl();
            //Getting url where image is stored
            //downloadUri will store image URI
        
    );

【讨论】:

【参考方案3】:

您正在使用已弃用的UploadTask.getDownloadUrl()。你可以使用StorageReference.getDownloadUrl()。

在你的情况下,你可以尝试this as -

 filepath.putFile(File).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() 
    @Override
    public void onSuccess(UploadTask.TaskSnapshot taskSnapshot)
    
         filepath.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() 
                    @Override
                    public void onSuccess(Uri uri) 
                        Uri downloadUrl = uri;
                       //Do what you want with the url
                    
        Toast.makeText(MtActivity.this, "Upload Done", Toast.LENGTH_LONG).show();
    
);

注意StorageReference.getDownloadUrl()返回的Task,必须异步处理,你不能做Uri downloadUrl = photoRef.getDownloadUrl().getResult();否则你会得到java.lang.IllegalStateException: Task is not yet complete

【讨论】:

String usableUrl = downloadUrl.toString(); Uri 之后 downloadUrl = uri; 为什么需要用getDownloadUrl() 附加addOnSuccessListener?由于上传文件的路径是一个非常小的字符串,我认为必须有一种方法可以从taskSnapshot 中检索到..putFile(...).addonSuccesslistener(.&lt;i.e here&gt;.) 中的路径? @anshsachdeva 您可以访问firebase.google.com/docs/storage/android/… 进行进一步挖掘。我认为您会发现此链接也很有帮助 - firebase.google.com/docs/reference/android/com/google/firebase/… 如果您找到其他出路添加/更新答案。【参考方案4】:

这个方法也行,而且简单一点。

这不是什么“不可思议”的事情,但它可以将您的代码减少到几行。希望这是一个有用的答案。

StorageReference filepath = mstorageRef.child("folder").child(filename);
filepath.putFile(File).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() 
        @Override
        public void onSuccess(UploadTask.TaskSnapshot taskSnapshot)
            Uri downloadUrl = filepath.getDownloadUrl();  // here is Url for photo  
            Toast.makeText(MtActivity.this, "Upload Done", Toast.LENGTH_LONG).show();
        
);

【讨论】:

【参考方案5】:

这里很热,我做到了

1) 这是我的上传和获取 http url 代码:

UploadTask uploadTask = FirebaseStorage.getInstance().getReference().child("id").child("filename")
                                .putFile(uri);
                        Task<Uri> urlTask = uploadTask.continueWithTask(new Continuation<UploadTask.TaskSnapshot, Task<Uri>>() 
                            @Override
                            public Task<Uri> then(@NonNull Task<UploadTask.TaskSnapshot> task) throws Exception 
                                if (!task.isSuccessful()) 
                                    throw task.getException();
                                

                                // Continue with the task to get the download URL
                                return FirebaseStorage.getInstance().getReference().child(user.getUid()).child(avatarName).getDownloadUrl();
                            
                        ).addOnCompleteListener(new OnCompleteListener<Uri>() 
                            @Override
                            public void onComplete(@NonNull Task<Uri> task) 
                                if (task.isSuccessful()) 
                                    Uri downloadUri = task.getResult();
                                    FirebaseDatabase.getInstance().getReference().child(user.getUid())
                                            .child(avatarName)
                                            .child("avatar_image")
                                            .setValue(downloadUri.toString());
                                    Toast.makeText(getContext(), "Success", Toast.LENGTH_SHORT).show();
                                 else 
                                    // Handle failures
                                    // ...
                                    Toast.makeText(getContext(), "Failed", Toast.LENGTH_SHORT).show();
                                
                            
                        );

2) 这是我从图库中提取图像后的 onActivityResult 代码

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) 
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null && data.getData() != null) 

        uri = data.getData();

        try 
            bitmap = MediaStore.Images.Media.getBitmap(getContext().getContentResolver(), uri);
            // Log.d(TAG, String.valueOf(bitmap));
            ivAvatarPic.setImageBitmap(bitmap);
            //ImageView imageView = (ImageView) findViewById(R.id.imageView);
            //imageView.setImageBitmap(bitmap);
         catch (IOException e) 
            e.printStackTrace();
        
    

【讨论】:

【参考方案6】:

如上所述,StorageReference.getDownloadUrl() 返回任务。

这是我的代码:

        filepath.putFile(imageUri).addOnCompleteListener(new OnCompleteListener<UploadTask.TaskSnapshot>() 
            @Override
            public void onComplete(@NonNull Task<UploadTask.TaskSnapshot> task) 
                if(task.isSuccessful())

                    filepath.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() 
                        @Override
                        public void onSuccess(Uri uri) 
                            Uri downloadUri = uri;
                            String download_url = uri.toString();
                            mUserDatabase.child("image").setValue(download_url).addOnCompleteListener(new OnCompleteListener<Void>() 
                              @Override

                                public void onComplete(@NonNull Task<Void> task) 

                                   if(task.isSuccessful()) 

                                          mProgressDialog.dismiss();
                                          Toast.makeText(SettingActivity.this, "Successfully uploaded", Toast.LENGTH_LONG).show();

                                   else 
                                       Toast.makeText(SettingActivity.this, "Error happened during the upload process", Toast.LENGTH_LONG).show();
                                   
                                
                            );
                        
                    );


                else
                    Toast.makeText(SettingActivity.this, "Error happened during the upload process", Toast.LENGTH_LONG ).show();
                
            
        );

【讨论】:

【参考方案7】:

使用以下代码

val imageGalleryRef = storageReference?.child(name + "_gallery")
            val uploadTask = imageGalleryRef.putFile(file)
            uploadTask.addOnFailureListener( e ->
                Log.e(TAG, "onFailure sendFileFirebase " + e.message)
            ).addOnCompleteListener(
                    object : OnCompleteListener<UploadTask.TaskSnapshot> 
                        override fun onComplete(p0: Task<UploadTask.TaskSnapshot>) 
                            imageGalleryRef.downloadUrl.addOnSuccessListener  e ->
                                run 
                                     downloadUrl = e.toString() // e is image download Uri
                                
                            
                        
                    

            )

【讨论】:

【参考方案8】:

试试这个:

 filepath.putFile(File).addOnCompleteListener(new OnCompleteListener<UploadTask.TaskSnapshot>() 
         @Override
         public void onComplete(@NonNull Task<UploadTask.TaskSnapshot> task) 
            if(task.isSuccessful())
                 String fileUri = task.getResult().getUploadSessionUri().toString();
                         // Do whatever you want with fileUri 

                        
                   
            ) ;

【讨论】:

【参考方案9】:
 filePath.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() 
                            @Override
                            public void onSuccess(Uri uri) 
                                String category = spinner.getSelectedItem().toString();
                                String title = ((EditText) findViewById(R.id.post_title)).getText().toString();
                                String description = ((EditText) findViewById(R.id.post_description)).getText().toString();
                                final Post post = new Post(userId, category, title, description, latitude, longitude, true);
                                post.setAddressList(addressLine);
                                post.setContact(contact);

                                if (addressLine != null) 
                                    post.setPlace(addressLine.split(",")[2]);
                                
                                post.setId(key);
                                post.setImage(uri.toString());
                                databaseReference.setValue(post).addOnCompleteListener(new OnCompleteListener<Void>() 
                                    @Override
                                    public void onComplete(@NonNull Task<Void> task) 
                                        if (task.isSuccessful()) 

                                            ((EditText) findViewById(R.id.post_title)).setText("");
                                            ((EditText) findViewById(R.id.post_description)).setText("");
                                            postImageButton.setImageURI(null);
                                            progressBarDialog.dismiss();
                                            Toast.makeText(PostActivity.this, "Your request is sucessfully completed", Toast.LENGTH_SHORT).show();
                                         else if (!task.isSuccessful()) 
                                            progressBarDialog.dismiss();
                                            Toast.makeText(PostActivity.this, "Your request is not completed", Toast.LENGTH_SHORT).show();
                                        

                                    
                                );
                            

                        );
                    

【讨论】:

【参考方案10】:

URI 更改为 URL

val urlTask = uploadTask.continueWith  task ->
            if (!task.isSuccessful) 
                task.exception?.let 
                    throw it
                
            


            spcaeRef.downloadUrl
        .addOnCompleteListener  task ->
            if (task.isSuccessful) 

                val downloadUri = task.result

                //URL
                val url = downloadUri!!.result

             else 
                //handle failure here
            
        

【讨论】:

【参考方案11】:

在 Ionic 5 + 电容器中,这就是我最终能够监控上传并获得最终文件名的方式。

代码是从 google 自己的文档 + 一些 google 搜索(https://ionicthemes.com/tutorials/about/ionic-firebase-image-upload 等)收集的。

它使用画布(据我了解)从图像生成 base64 字符串。这行得通,而 ionic 的 File 和 Base64 却没有。

在页面上,我有一个 显示百分比 (this.downloadProgress) 如果它 > 0。我还有一个带有 src=this.imageUrl 的 显示图片已上传。

我无法使上述答案中的任何技术发挥作用,甚至无法编译。但我不知道为什么。

另一个需要注意的是,一些示例代码使用了 function() 而不是箭头语法

encodeImageUri(imageURI, function(image64)

需要重写箭头语法以将“this”绑定/传递给调用的函数,如下所示:

encodeImageUri(imageURI, image64 =>

    uploadImage(imageURI) 
    console.log(`try upload $imageURI`)
      let storageRef = firebase.storage().ref();
      let imageRef = storageRef.child('image').child('imageName');
      this.encodeImageUri(imageURI, image64 => 

        // create upload task
        const uplTask = imageRef.putString(image64, 'data_url');

        uplTask.on('state_changed',
          snapshot => 
            var progress = (snapshot.bytesTransferred / snapshot.totalBytes);
            console.log('Upload is ' + progress * 100 + '% done'); // might display this somewhere
            this.downloadProgress = progress; // update progress bar
          ,
          error => 
            console.log('upload error');
          ,
          () => 
            uplTask.snapshot.ref.getDownloadURL()
              .then(downloadURL => 
                console.log('File available at', downloadURL);
                this.imageUrl = downloadURL;
                this.downloadProgress = -1; // negative values hide the progress bar
              );        
          
        );
      );
  

  encodeImageUri(imageUri, callback) 
    var c = document.createElement('canvas');
    var ctx = c.getContext("2d");
    var img = new Image();
    img.onload = function () 
      var aux:any = this;
      c.width = aux.width;
      c.height = aux.height;
      ctx.drawImage(img, 0, 0);
      var dataURL = c.toDataURL("image/jpeg");
      callback(dataURL);
    ;
    img.src = imageUri;
  ;

当然这有点无聊,因为它总是覆盖同一个 Firebase 存储文件 :) 但这是可以修复的。

【讨论】:

【参考方案12】:

不确定这是否是您正在寻找的,因为我正在使用 Kotlin。这就是在我当前的项目中对我有用的方法。我希望它会在未来对其他人有所帮助。

首先,我从相机或图库中获取图像。 我正在使用当前时间戳使文件名唯一。

fun uploadFileFromMemory() 

        showLoading()

        val currentTimestamp = System.currentTimeMillis()

        val storage = Firebase.storage("Your storage url")

        // Create a storage reference from our app
        val storageRef = storage.reference

        // Create a reference to "mountains.jpg"
        val mountainsRef = storageRef.child("images/picture$currentTimestamp.jpg")

        // Get the data from an adminImageView as bytes
        adminImageView.isDrawingCacheEnabled = true
        adminImageView.buildDrawingCache()
        val bitmap = (adminImageView.drawable as BitmapDrawable).bitmap
        val baos = ByteArrayOutputStream()
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos)
        val data = baos.toByteArray()

        var uploadTask = mountainsRef.putBytes(data)

        val urlTask = uploadTask.continueWithTask  task ->
            if (!task.isSuccessful) 
                task.exception?.let 
                    throw it
                
            
            mountainsRef.downloadUrl
        .addOnCompleteListener  task ->
            if (task.isSuccessful) 
                val downloadUri = task.result

                updateServicePicture(downloadUri.toString())

             else 
                hideLoading()

                showToast("Something went wrong")
            
        

之后,我将获取新更新文件的 URL,以使用此函数更新我的 firestore 数据库中的图片 URL 属性。

fun updateServicePicture(url: String) 

        val db = FirebaseFirestore.getInstance()

        val id = arguments?.getString("id")

        if (id !== null) 

            val ref = db.collection("services").document(id)

// Set the "isCapital" field of the city 'DC'
            ref
                .update("picture", url)
                .addOnSuccessListener  Log.d(TAG, "DocumentSnapshot successfully updated!")

                    hideLoading()

                    showToast("Picture has been successfully updated")
                
                .addOnFailureListener  e -> Log.w(TAG, "Error updating document", e)

                    hideLoading()

                    showToast("Something went wrong")
                

        
    

hideLoading()、showloading() 和 showToast() 是我的进度条和 toast 函数。 我希望这可以帮助某人。 通过文档和一些测试,我最终让它工作了。祝大家编码愉快。

【讨论】:

【参考方案13】:
  Future<List<String>> uploadImages(List<String> filepaths) async 
    List<String> uploadUrls = [];

    await Future.wait(filepaths.map((String filepath) async 
      FirebaseStorage storage = FirebaseStorage(storageBucket: 'gs://your-bucket-name.appspot.com');
      StorageUploadTask uploadTask = storage.ref().child("images/$basename(filepath)").putFile(File(filepath));
      StorageTaskSnapshot storageTaskSnapshot;

      StorageTaskSnapshot snapshot = await uploadTask.onComplete;
      if (snapshot.error == null) 
        storageTaskSnapshot = snapshot;
        final String downloadUrl = await storageTaskSnapshot.ref.getDownloadURL();
        uploadUrls.add(downloadUrl);

        print('Upload success');
       else 
        print('Error from image repo $snapshot.error.toString()');
        throw ('This file is not an image');
      
    ), eagerError: true, cleanUp: (_) 
      print('eager cleaned up');
    );

    return uploadUrls;
  

【讨论】:

以上是关于将文件上传到 Firebase 后如何获取文件 URL?的主要内容,如果未能解决你的问题,请参考以下文章

Angular 6 - 上传后获取 Firebase 存储文件的下载 URL

将图像上传到 Firebase 存储后如何获取图像 uri?

如何将一组图像上传到 Firebase 存储?

将文件上传到 Firebase 存储错误 404 -“未找到。无法获取对象”

上传到 Firebase 存储时如何使用 Cloud Functions for FIrebase 获取 mp3 文件的持续时间

如何通过 android 将文件保存到 Firebase 托管文件夹位置以获取图像?