将文件上传到 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(.<i.e here>.)
中的路径?
@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 却没有。
在页面上,我有一个
我无法使上述答案中的任何技术发挥作用,甚至无法编译。但我不知道为什么。
另一个需要注意的是,一些示例代码使用了 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 存储错误 404 -“未找到。无法获取对象”
上传到 Firebase 存储时如何使用 Cloud Functions for FIrebase 获取 mp3 文件的持续时间