Estou trabalhando no upload de imagens, tudo funciona muito bem, mas tenho 100 fotos e gostaria de mostrar todas na minha View
, como recebo a lista completa das imagens em uma pasta, não consigo encontrar nenhuma API para isso trabalhos.
Estou trabalhando no upload de imagens, tudo funciona muito bem, mas tenho 100 fotos e gostaria de mostrar todas na minha View
, como recebo a lista completa das imagens em uma pasta, não consigo encontrar nenhuma API para isso trabalhos.
Respostas:
Desde Firebase SDKs para JavaScript versão 6.1 , iOS versão 6.4 e Android versão 18.1, todos têm um método para listar arquivos.
A documentação é um pouco esparsa até agora, então recomendo conferir a resposta de Rosário para mais detalhes.
Resposta anterior, uma vez que esta abordagem ainda pode ser útil às vezes:
No momento, não há chamada de API no Firebase SDK para listar todos os arquivos em uma pasta do Cloud Storage de um aplicativo. Se precisar dessa funcionalidade, você deve armazenar os metadados dos arquivos (como os URLs de download) em um local onde possa listá-los. O Firebase Realtime Database e o Cloud Firestore são perfeitos para isso e permitem que você também compartilhe facilmente os URLs com outras pessoas.
Você pode encontrar uma boa amostra (mas um tanto envolvente) disso em nosso aplicativo de amostra FriendlyPix . O código relevante para a versão web está aqui , mas também existem versões para iOS e Android.
Desde maio de 2019, a versão 6.1.0 do Firebase SDK para Cloud Storage agora é compatível com a listagem de todos os objetos de um intervalo. Você só precisa ligar listAll()
para um Reference
:
// Since you mentioned your images are in a folder,
// we'll create a Reference to that folder:
var storageRef = firebase.storage().ref("your_folder");
// Now we get the references of these images
storageRef.listAll().then(function(result) {
result.items.forEach(function(imageRef) {
// And finally display them
displayImage(imageRef);
});
}).catch(function(error) {
// Handle any errors
});
function displayImage(imageRef) {
imageRef.getDownloadURL().then(function(url) {
// TODO: Display the image on the UI
}).catch(function(error) {
// Handle any errors
});
}
Por favor , note que para utilizar esta função, você deve opt-in para a versão 2 de regras de segurança , que pode ser feito, fazendo rules_version = '2';
a primeira linha de suas regras de segurança:
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
Eu recomendo verificar os documentos para referência futura.
Além disso, de acordo com a configuração , na Etapa 5, este script não é permitido, Node.js
pois require("firebase/app");
não retorna firebase.storage()
como uma função. Isso só é conseguido usando import * as firebase from 'firebase/app';
.
Desde março de 2017: com a adição do Firebase Cloud Functions e a integração mais profunda do Firebase com o Google Cloud, isso agora é possível.
Com o Cloud Functions, você pode usar o pacote Google Cloud Node para fazer operações épicas no Cloud Storage. Abaixo está um exemplo que obtém todos os URLs de arquivo em uma matriz do Cloud Storage. Esta função será acionada sempre que algo for salvo no armazenamento em nuvem do Google.
Nota 1 : esta é uma operação bastante dispendiosa do ponto de vista computacional, pois tem que percorrer todos os arquivos em um intervalo / pasta.
Nota 2 : Escrevi isso apenas como exemplo, sem dedicar muitos detalhes às promessas etc. Só para dar uma ideia.
const functions = require('firebase-functions');
const gcs = require('@google-cloud/storage')();
// let's trigger this function with a file upload to google cloud storage
exports.fileUploaded = functions.storage.object().onChange(event => {
const object = event.data; // the object that was just uploaded
const bucket = gcs.bucket(object.bucket);
const signedUrlConfig = { action: 'read', expires: '03-17-2025' }; // this is a signed url configuration object
var fileURLs = []; // array to hold all file urls
// this is just for the sake of this example. Ideally you should get the path from the object that is uploaded :)
const folderPath = "a/path/you/want/its/folder/size/calculated";
bucket.getFiles({ prefix: folderPath }, function(err, files) {
// files = array of file objects
// not the contents of these files, we're not downloading the files.
files.forEach(function(file) {
file.getSignedUrl(signedUrlConfig, function(err, fileURL) {
console.log(fileURL);
fileURLs.push(fileURL);
});
});
});
});
Espero que isso lhe dê uma ideia geral. Para melhores exemplos de funções de nuvem, confira o repositório Github do Google cheio de exemplos de funções de nuvem para Firebase . Verifique também a documentação da API do Google Cloud Node
.then
como este:this.bucket .getFiles({ prefix: 'path/to/directory' }) .then((arr) => {})
Como não há idioma listado, responderei em Swift. É altamente recomendável usar o Firebase Storage e o Firebase Realtime Database juntos para realizar listas de downloads:
Compartilhado:
// Firebase services
var database: FIRDatabase!
var storage: FIRStorage!
...
// Initialize Database, Auth, Storage
database = FIRDatabase.database()
storage = FIRStorage.storage()
...
// Initialize an array for your pictures
var picArray: [UIImage]()
Envio:
let fileData = NSData() // get data...
let storageRef = storage.reference().child("myFiles/myFile")
storageRef.putData(fileData).observeStatus(.Success) { (snapshot) in
// When the image has successfully uploaded, we get it's download URL
let downloadURL = snapshot.metadata?.downloadURL()?.absoluteString
// Write the download URL to the Realtime Database
let dbRef = database.reference().child("myFiles/myFile")
dbRef.setValue(downloadURL)
}
Baixar:
let dbRef = database.reference().child("myFiles")
dbRef.observeEventType(.ChildAdded, withBlock: { (snapshot) in
// Get download URL from snapshot
let downloadURL = snapshot.value() as! String
// Create a storage reference from the URL
let storageRef = storage.referenceFromURL(downloadURL)
// Download the data, assuming a max size of 1MB (you can change this as necessary)
storageRef.dataWithMaxSize(1 * 1024 * 1024) { (data, error) -> Void in
// Create a UIImage, add it to the array
let pic = UIImage(data: data)
picArray.append(pic)
})
})
Para obter mais informações, consulte Zero to App: Develop with Firebase , e seu código-fonte associado , para um exemplo prático de como fazer isso.
Uma solução alternativa pode ser criar um arquivo (ou seja, list.txt) sem nada dentro, neste arquivo você pode definir os metadados personalizados (ou seja, um Mapa <String, String>) com a lista de todos os URLs do arquivo.
Portanto, se você precisar fazer o downlaod de todos os arquivos em um feed, primeiro faça o download dos metadados do arquivo list.txt e, em seguida, itere os dados personalizados e faça o download de todos os arquivos com os URLs no mapa.
Eu também encontrei esse problema quando estava trabalhando em meu projeto. Eu realmente gostaria que eles fornecessem um método API final. Enfim, foi assim que eu fiz: quando você estiver carregando uma imagem para o armazenamento do Firebase, crie um objeto e passe esse objeto para o banco de dados do Firebase ao mesmo tempo. Este objeto contém o URI de download da imagem.
trailsRef.putFile(file).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
@Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
Uri downloadUri = taskSnapshot.getDownloadUrl();
DatabaseReference myRef = database.getReference().child("trails").child(trail.getUnique_id()).push();
Image img = new Image(trail.getUnique_id(), downloadUri.toString());
myRef.setValue(img);
}
});
Posteriormente, quando quiser baixar imagens de uma pasta, basta iterar os arquivos dessa pasta. Esta pasta tem o mesmo nome que a "pasta" no Firebase storage, mas você pode nomeá-la como quiser. Eu os coloquei em uma discussão separada.
@Override
protected List<Image> doInBackground(Trail... params) {
String trialId = params[0].getUnique_id();
mDatabase = FirebaseDatabase.getInstance().getReference();
mDatabase.child("trails").child(trialId).addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
images = new ArrayList<>();
Iterator<DataSnapshot> iter = dataSnapshot.getChildren().iterator();
while (iter.hasNext()) {
Image img = iter.next().getValue(Image.class);
images.add(img);
}
isFinished = true;
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
Agora que tenho uma lista de objetos contendo os URIs para cada imagem, posso fazer o que quiser com eles. Para carregá-los em imageView, criei outro thread.
@Override
protected List<Bitmap> doInBackground(List<Image>... params) {
List<Bitmap> bitmaps = new ArrayList<>();
for (int i = 0; i < params[0].size(); i++) {
try {
URL url = new URL(params[0].get(i).getImgUrl());
Bitmap bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
bitmaps.add(bmp);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return bitmaps;
}
Isso retorna uma lista de Bitmap, quando termina eu simplesmente os anexei ao ImageView na atividade principal. Os métodos abaixo são @Override porque eu tenho interfaces criadas e escuto a conclusão em outros threads.
@Override
public void processFinishForBitmap(List<Bitmap> bitmaps) {
List<ImageView> imageViews = new ArrayList<>();
View v;
for (int i = 0; i < bitmaps.size(); i++) {
v = mInflater.inflate(R.layout.gallery_item, mGallery, false);
imageViews.add((ImageView) v.findViewById(R.id.id_index_gallery_item_image));
imageViews.get(i).setImageBitmap(bitmaps.get(i));
mGallery.addView(v);
}
}
Observe que eu tenho que esperar que a imagem da lista seja retornada primeiro e depois chamar o thread para trabalhar no bitmap da lista. Nesse caso, a imagem contém o URI.
@Override
public void processFinish(List<Image> results) {
Log.e(TAG, "get back " + results.size());
LoadImageFromUrlTask loadImageFromUrlTask = new LoadImageFromUrlTask();
loadImageFromUrlTask.delegate = this;
loadImageFromUrlTask.execute(results);
}
Espero que alguém ache útil. Também servirá como uma linha de guilda para mim no futuro.
Mais uma maneira de adicionar a imagem ao banco de dados usando o Cloud Function para rastrear todas as imagens enviadas e armazená-las no banco de dados.
exports.fileUploaded = functions.storage.object().onChange(event => {
const object = event.data; // the object that was just uploaded
const contentType = event.data.contentType; // This is the image Mimme type\
// Exit if this is triggered on a file that is not an image.
if (!contentType.startsWith('image/')) {
console.log('This is not an image.');
return null;
}
// Get the Signed URLs for the thumbnail and original image.
const config = {
action: 'read',
expires: '03-01-2500'
};
const bucket = gcs.bucket(event.data.bucket);
const filePath = event.data.name;
const file = bucket.file(filePath);
file.getSignedUrl(config, function(err, fileURL) {
console.log(fileURL);
admin.database().ref('images').push({
src: fileURL
});
});
});
Código completo aqui: https://gist.github.com/bossly/fb03686f2cb1699c2717a0359880cf84
Para o node js, usei este código
const Storage = require('@google-cloud/storage');
const storage = new Storage({projectId: 'PROJECT_ID', keyFilename: 'D:\\keyFileName.json'});
const bucket = storage.bucket('project.appspot.com'); //gs://project.appspot.com
bucket.getFiles().then(results => {
const files = results[0];
console.log('Total files:', files.length);
files.forEach(file => {
file.download({destination: `D:\\${file}`}).catch(error => console.log('Error: ', error))
});
}).catch(err => {
console.error('ERROR:', err);
});
Você pode listar arquivos em um diretório de armazenamento do firebase pelo método listAll (). Para usar este método, é necessário implementar esta versão do Firebase Storage. 'com.google.firebase: firebase-storage: 18.1.1'
https://firebase.google.com/docs/storage/android/list-files
Lembre-se de atualizar as Regras de segurança para a versão 2.
Na verdade, isso é possível, mas apenas com uma API do Google Cloud em vez de uma do Firebase. É porque um Firebase Storage é um Google Cloud Storage Bucket que pode ser facilmente alcançado com as APIs do Google Cloud. No entanto, você precisa usar OAuth para autenticação em vez do Firebase.
Eu enfrentei o mesmo problema, o meu é ainda mais complicado.
O administrador fará o upload dos arquivos de áudio e PDF para o armazenamento:
arquivos audios / season1, season2 ... / class1, class 2 / .mp3
livros / arquivos .pdf
O aplicativo Android precisa obter a lista de subpastas e arquivos.
A solução é capturar o evento de upload no armazenamento e criar a mesma estrutura no firestore usando a função de nuvem.
Etapa 1: Crie manualmente a coleção de 'armazenamento' e o documento 'áudios / livros' no Firestore
Etapa 2: configurar a função de nuvem
Pode levar cerca de 15 minutos: https://www.youtube.com/watch?v=DYfP-UIKxH0&list=PLl-K7zZEsYLkPZHe41m4jfAxUi0JjLgSM&index=1
Etapa 3: capturar o evento de upload usando a função de nuvem
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp(functions.config().firebase);
const path = require('path');
export const onFileUpload = functions.storage.object().onFinalize(async (object) => {
let filePath = object.name; // File path in the bucket.
const contentType = object.contentType; // File content type.
const metageneration = object.metageneration; // Number of times metadata has been generated. New objects have a value of 1.
if (metageneration !== "1") return;
// Get the file name.
const fileName = path.basename(filePath);
filePath = filePath.substring(0, filePath.length - 1);
console.log('contentType ' + contentType);
console.log('fileName ' + fileName);
console.log('filePath ' + filePath);
console.log('path.dirname(filePath) ' + path.dirname(filePath));
filePath = path.dirname(filePath);
const pathArray = filePath.split("/");
let ref = '';
for (const item of pathArray) {
if (ref.length === 0) {
ref = item;
}
else {
ref = ref.concat('/sub/').concat(item);
}
}
ref = 'storage/'.concat(ref).concat('/sub')
admin.firestore().collection(ref).doc(fileName).create({})
.then(result => {console.log('onFileUpload:updated')})
.catch(error => {
console.log(error);
});
});
Etapa 4: recuperar a lista de pastas / arquivos no aplicativo Android usando o firestore
private static final String STORAGE_DOC = "storage/";
public static void getMediaCollection(String path, OnCompleteListener onCompleteListener) {
String[] pathArray = path.split("/");
String doc = null;
for (String item : pathArray) {
if (TextUtils.isEmpty(doc)) doc = STORAGE_DOC.concat(item);
else doc = doc.concat("/sub/").concat(item);
}
doc = doc.concat("/sub");
getFirestore().collection(doc).get().addOnCompleteListener(onCompleteListener);
}
Etapa 5: obter url de download
public static void downloadMediaFile(String path, OnCompleteListener<Uri> onCompleteListener) {
getStorage().getReference().child(path).getDownloadUrl().addOnCompleteListener(onCompleteListener);
}
Nota
Temos que colocar "sub" coleção para cada item, pois o firestore não oferece suporte para recuperar a lista de coleção.
Levei 3 dias para descobrir a solução, espero que leve 3 horas no máximo.
Felicidades.
Prolongando a resposta de Rosário Pereira Fernandes , para uma solução JavaScript:
npm install -g firebase-tools
JavaScript
como idioma padrão npm install --save firebase
npm install @google-cloud/storage
npm install @google-cloud/firestore
... <any other dependency needed>
"firebase": "^6.3.3",
"@google-cloud/storage": "^3.0.3"
functions / package.json
{
"name": "functions",
"description": "Cloud Functions for Firebase",
"scripts": {
"lint": "eslint .",
"serve": "firebase serve --only functions",
"shell": "firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"
},
"engines": {
"node": "10"
},
"dependencies": {
"@google-cloud/storage": "^3.0.3",
"firebase": "^6.3.3",
"firebase-admin": "^8.0.0",
"firebase-functions": "^3.1.0"
},
"devDependencies": {
"eslint": "^5.12.0",
"eslint-plugin-promise": "^4.0.1",
"firebase-functions-test": "^0.1.6"
},
"private": true
}
listAll
funçãoindex.js
var serviceAccount = require("./key.json");
const functions = require('firebase-functions');
const images = require('./images.js');
var admin = require("firebase-admin");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://<my_project>.firebaseio.com"
});
const bucket = admin.storage().bucket('<my_bucket>.appspot.com')
exports.getImages = functions.https.onRequest((request, response) => {
images.getImages(bucket)
.then(urls => response.status(200).send({ data: { urls } }))
.catch(err => console.error(err));
})
images.js
module.exports = {
getImages
}
const query = {
directory: 'images'
};
function getImages(bucket) {
return bucket.getFiles(query)
.then(response => getUrls(response))
.catch(err => console.error(err));
}
function getUrls(response) {
const promises = []
response.forEach( files => {
files.forEach (file => {
promises.push(getSignedUrl(file));
});
});
return Promise.all(promises).then(result => getParsedUrls(result));
}
function getSignedUrl(file) {
return file.getSignedUrl({
action: 'read',
expires: '09-01-2019'
})
}
function getParsedUrls(result) {
return JSON.stringify(result.map(mediaLink => createMedia(mediaLink)));
}
function createMedia(mediaLink) {
const reference = {};
reference.mediaLink = mediaLink[0];
return reference;
}
firebase deploy
para carregar sua função de nuvembuild.gradle
dependencies {
...
implementation 'com.google.firebase:firebase-functions:18.1.0'
...
}
aula de kotlin
private val functions = FirebaseFunctions.getInstance()
val cloudFunction = functions.getHttpsCallable("getImages")
cloudFunction.call().addOnSuccessListener {...}
Em relação ao desenvolvimento deste recurso, encontrei alguns problemas que podem ser encontrados aqui .
Para fazer isso com JS
Você pode anexá-los diretamente ao seu contêiner div ou pode enviá-los para uma matriz. A seguir, você verá como anexá-los ao seu div.
1) Ao armazenar suas imagens no armazenamento, crie uma referência à imagem em seu banco de dados Firebase com a seguinte estrutura
/images/(imageName){
description: "" ,
imageSrc : (imageSource)
}
2) Quando você carrega o documento, extraia todos os URLs de origem da imagem do banco de dados, em vez do armazenamento com o seguinte código
$(document).ready(function(){
var query = firebase.database().ref('images/').orderByKey();
query.once("value").then(function(snapshot){
snapshot.forEach(function(childSnapshot){
var imageName = childSnapshot.key;
var childData = childSnapshot.val();
var imageSource = childData.url;
$('#imageGallery').append("<div><img src='"+imageSource+"'/></div>");
})
})
});
Você pode usar o seguinte código. Aqui, estou enviando a imagem para o armazenamento do firebase e, em seguida, estou armazenando o url de download da imagem no banco de dados do firebase.
//getting the storage reference
StorageReference sRef = storageReference.child(Constants.STORAGE_PATH_UPLOADS + System.currentTimeMillis() + "." + getFileExtension(filePath));
//adding the file to reference
sRef.putFile(filePath)
.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
@Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
//dismissing the progress dialog
progressDialog.dismiss();
//displaying success toast
Toast.makeText(getApplicationContext(), "File Uploaded ", Toast.LENGTH_LONG).show();
//creating the upload object to store uploaded image details
Upload upload = new Upload(editTextName.getText().toString().trim(), taskSnapshot.getDownloadUrl().toString());
//adding an upload to firebase database
String uploadId = mDatabase.push().getKey();
mDatabase.child(uploadId).setValue(upload);
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception exception) {
progressDialog.dismiss();
Toast.makeText(getApplicationContext(), exception.getMessage(), Toast.LENGTH_LONG).show();
}
})
.addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
@Override
public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
//displaying the upload progress
double progress = (100.0 * taskSnapshot.getBytesTransferred()) / taskSnapshot.getTotalByteCount();
progressDialog.setMessage("Uploaded " + ((int) progress) + "%...");
}
});
Agora, para buscar todas as imagens armazenadas no banco de dados do firebase, você pode usar
//adding an event listener to fetch values
mDatabase.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot snapshot) {
//dismissing the progress dialog
progressDialog.dismiss();
//iterating through all the values in database
for (DataSnapshot postSnapshot : snapshot.getChildren()) {
Upload upload = postSnapshot.getValue(Upload.class);
uploads.add(upload);
}
//creating adapter
adapter = new MyAdapter(getApplicationContext(), uploads);
//adding adapter to recyclerview
recyclerView.setAdapter(adapter);
}
@Override
public void onCancelled(DatabaseError databaseError) {
progressDialog.dismiss();
}
});
Para mais detalhes, você pode ver meu exemplo de armazenamento de Firebase post .
Então, eu tinha um projeto que exigia o download de recursos do armazenamento do Firebase, então tive que resolver esse problema sozinho. Aqui está como :
1- Primeiro, faça um modelo de dados por exemplo class Choice{}
, nessa classe define uma variável String chamada nome da imagem para que seja assim
class Choice {
.....
String imageName;
}
2- a partir de um banco de dados / banco de dados firebase, codifique os nomes das imagens para os objetos, portanto, se você tiver um nome de imagem chamado Apple.png, crie o objeto a ser
Choice myChoice = new Choice(...,....,"Apple.png");
3- Agora, obtenha o link para os ativos em seu armazenamento do Firebase, que será algo parecido com isso
gs://your-project-name.appspot.com/
4 - por fim, inicialize sua referência de armazenamento firebase e comece a obter os arquivos por um loop como esse
storageRef = storage.getReferenceFromUrl(firebaseRefURL).child(imagePath);
File localFile = File.createTempFile("images", "png");
storageRef.getFile(localFile).addOnSuccessListener(new OnSuccessListener<FileDownloadTask.TaskSnapshot>() {
@Override
public void onSuccess(FileDownloadTask.TaskSnapshot taskSnapshot) {
//Dismiss Progress Dialog\\
}
5- é isso
#In Python
import firebase_admin
from firebase_admin import credentials
from firebase_admin import storage
import datetime
import urllib.request
def image_download(url, name_img) :
urllib.request.urlretrieve(url, name_img)
cred = credentials.Certificate("credentials.json")
# Initialize the app with a service account, granting admin privileges
app = firebase_admin.initialize_app(cred, {
'storageBucket': 'YOURSTORAGEBUCKETNAME.appspot.com',
})
url_img = "gs://YOURSTORAGEBUCKETNAME.appspot.com/"
bucket_1 = storage.bucket(app=app)
image_urls = []
for blob in bucket_1.list_blobs():
name = str(blob.name)
#print(name)
blob_img = bucket_1.blob(name)
X_url = blob_img.generate_signed_url(datetime.timedelta(seconds = 300), method='GET')
#print(X_url)
image_urls.append(X_url)
PATH = ['Where you want to save the image']
for path in PATH:
i = 1
for url in image_urls:
name_img = str(path + "image"+str(i)+".jpg")
image_download(url, name_img)
i+=1
Estou usando AngularFire
e uso o seguinte para obter todos osdownloadURL
getPhotos(id: string): Observable<string[]> {
const ref = this.storage.ref(`photos/${id}`)
return ref.listAll().pipe(switchMap(list => {
const calls: Promise<string>[] = [];
list.items.forEach(item => calls.push(item.getDownloadURL()))
return Promise.all(calls)
}));
}
Para Android, a melhor prática é usar FirebaseUI e Glide.
Você precisa adicionar isso ao seu gradle / app para obter a biblioteca. Observe que ele já tem o Glide nele!
implementation 'com.firebaseui:firebase-ui-storage:4.1.0'
E então, em seu código, use
// Reference to an image file in Cloud Storage
StorageReference storageReference = FirebaseStorage.getInstance().getReference();
// ImageView in your Activity
ImageView imageView = findViewById(R.id.imageView);
// Download directly from StorageReference using Glide
// (See MyAppGlideModule for Loader registration)
GlideApp.with(this /* context */)
.load(storageReference)
.into(imageView);