Firebase 存储教程

Firebase 云端存储 (Cloud Storage) 是 Google 官方提供的一项功能强大、操作简单且经济实惠的对象存储服务,可轻松支持类似 Google 这种规模级别的应用。无论网络质量如何,适用于 Cloud Storage 的 Firebase SDK 都能为 Firebase 应用提供 Google 安全品质的文件上传和下载服务。可以使用 SDK 来存储图片、音频、视频或其他由用户生成的内容。在服务器上,可以使用 Google Cloud Storage 来访问相同的文件。

准备工作

  1. 注册成为 Firebase 开发者
    Firebase Console 注册账号并登陆。
  2. 添加项目
    点击 “添加项目”,填写项目名称和国家 / 地区。添加完成后进入项目。
  3. 添加应用
    在此只演示安卓系统,点击 “Overview 概览” 页面的 “将 Firebase 添加到您的 Android 应用” 按钮。填写 Android 应用包名(不可更改),别名(选填),调试签名证书 SHA1(可选)。
  4. 下载配置文件
    点击 “注册应用”,下载配置文件 “google-services.json”。(此配置文件也可以在 Overview 的右边设置中的 “项目设置” 中查看、下载。)
    在 Android Studio 中切换到项目视图,查看项目根目录(即 app 目录),并将配置文件放入到此根目录下。

服务器端

本文使用 Python 作为服务器脚本语言。
Google Cloud Storage 源码:Google Cloud StorageAPI Document

环境配置

pip 方式:pip install firebase_admin

服务端主函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import os
import firebase_admin
from firebase_admin import credentials
from firebase_admin import storage

cred = credentials.Certificate('path/to/serviceAccountKey.json')
firebase_admin.initialize_app(cred, {
'storageBucket': '<BUCKET_NAME>.appspot.com'
})
bucket = storage.bucket()

blob = bucket.blob('path/to/file')
file_string = blob.download_as_string() #以字符串的形式打印存储的文件
with open('path/to/file', 'wb') as file:
blob.download_to_file(file) #以byte的形式下载文件到本地

blobs_list = list(bucket.list_blobs(prefix='xxx')) #以blob形式返回以’xxx‘为前缀的文件列表

Android 上的 Cloud Storage

前提条件:

  1. 安装 Firebase SDK。
  2. 在 Firebase 控制台中将应用添加到 Firebase 项目。

设置公共访问权限

Cloud Storage for Firebase 提供了一种声明式规则语言,可用于定义数据的组织结构方式、将数据编入索引的方式,以及何时可以读取和写入数据。默认情况下,对 Storage 的读写权限是有限制的,只有通过身份验证的用户才能读写数据。要在不设置身份验证的情况下开始使用 Storage,可以将规则配置为允许公共访问。

  1. 进入 firebase 控制台
  2. 进入 firebase 项目
  3. 左侧栏中点击 “Develop-Storage”
  4. 选项卡中选择 “规则”
  5. 右侧改写规则为公开规则:
    1
    2
    3
    4
    5
    6
    7
    service firebase.storage {
    match /b/{bucket}/o {
    match /{allPaths=**} {
    allow read, write;
    }
    }
    }

这会使得 Storage 向所有人开放,包括不使用应用的用户,因此在设置身份验证时,请务必重新限制对 Storage 的访问权限。

Android 客户端

官方集成文档:Android 上的 Cloud Storage 使用入门

添加所需的依赖

  1. 向根项目级 build.gradle 文件添加规则,以纳入 Google 服务插件:
    1
    2
    3
    4
    5
    6
    7
    buildscript {
    // ...
    dependencies {
    // ...
    classpath 'com.google.gms:google-services:4.3.3' #修改为最新版本
    }
    }
  2. 在模块 Gradle 文件(通常是 app/build.gradle)中,在文件的底部添加 apply plugin 代码行,以启用 Gradle 插件:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    apply plugin: 'com.android.application'
    apply plugin: 'com.google.gms.google-services'

    android {
    // ...
    }
    dependencies {
    // ...
    implementation 'com.google.firebase:firebase-storage:19.1.1' #修改为最新版本
    implementation "com.google.firebase:firebase-storage-ktx:19.1.1" #如果是kotlin语言则加上-ktx,修改为最新版本
    }

设置 Cloud Storage

访问存储分区的第一步是在 onCreate 函数中创建一个 FirebaseStorage 实例:

1
FirebaseStorage storage = FirebaseStorage.getInstance();

1
val storage = Firebase.storage

创建引用

要上传、下载或删除文件,或要获取或更新文件的元数据,请创建引用。引用可以看作是指向云端文件的指针。由于引用属于轻型项目,因此可以根据需要创建多个引用。 这些引用可以重复用于多个操作。

引用是使用 FirebaseStorage 单例实例并调用其 getReference () 方法创建的。

1
StorageReference storageRef = storage.getReference();

1
val storageRef = storage.reference

可以在现有引用上使用 getChild () 方法,创建一个对树中较低位置的引用。比如文件存储在‘aaa’文件夹下‘bbb’文件中,则:

1
StorageReference fileRef = storageRef.child("aaa/bbb");

1
val riversRef = storageRef.child("aaa/bbb")

上传

要将文件上传到 Cloud Storage,首先要创建对文件的完整路径(包括文件名)的引用。
创建适当的引用后,可以调用 putBytes ()、putFile () 或 putStream () 方法将文件上传到 Cloud Storage。

通过内存中的数据上传

putBytes () 方法是将文件上传到 Cloud Storage 的最简单方法。putBytes () 需要一个 byte [] 并返回 UploadTask,可以用它来管理和监控上传状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
byte[] data;

UploadTask uploadTask = mountainsRef.putBytes(data);
uploadTask.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception exception) {
// Handle unsuccessful uploads
}
}).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
@Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
// taskSnapshot.getMetadata() contains file metadata such as size, content-type, etc.
// ...
}
});

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Get the data from an ImageView as bytes
imageView.isDrawingCacheEnabled = true
imageView.buildDrawingCache()
val bitmap = (imageView.drawable as BitmapDrawable).bitmap
val baos = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos)
val data = baos.toByteArray()

var uploadTask = mountainsRef.putBytes(data)
uploadTask.addOnFailureListener {
// Handle unsuccessful uploads
}.addOnSuccessListener {
// taskSnapshot.metadata contains file metadata such as size, content-type, etc.
// ...
}

由于 putBytes () 接受了 byte [],因此它需要应用立即将文件的全部内容保存在内存中。请考虑使用 putStream () 或 putFile () 以使用较少的内存。

通过数据流上传

putStream () 方法是将文件上传到 Cloud Storage 最通用的方法。putStream () 接受了 InputStream 并返回 UploadTask,可以使用它来管理和监控上传状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
InputStream stream = new FileInputStream(new File("path/to/file"));

uploadTask = mountainsRef.putStream(stream);
uploadTask.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception exception) {
// Handle unsuccessful uploads
}
}).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
@Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
// taskSnapshot.getMetadata() contains file metadata such as size, content-type, etc.
// ...
}
});

1
2
3
4
5
6
7
8
9
val stream = FileInputStream(File("path/to/file"))

uploadTask = mountainsRef.putStream(stream)
uploadTask.addOnFailureListener {
// Handle unsuccessful uploads
}.addOnSuccessListener {
// taskSnapshot.metadata contains file metadata such as size, content-type, etc.
// ...
}

从本地文件上传

可以使用 putFile () 方法上传设备上的本地文件,例如相机中的照片和视频。putFile () 需要一个 File 并返回 UploadTask,可以使用它来管理和监控上传状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Uri file = Uri.fromFile(new File("path/to/file"));
StorageReference fileRef = storageRef.child("folder/"+file.getLastPathSegment());
uploadTask = fileRef.putFile(file);

// Register observers to listen for when the download is done or if it fails
uploadTask.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception exception) {
// Handle unsuccessful uploads
}
}).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
@Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
// taskSnapshot.getMetadata() contains file metadata such as size, content-type, etc.
// ...
}
});

1
2
3
4
5
6
7
8
9
10
11
var file = Uri.fromFile(File("path/to/file"))
val riversRef = storageRef.child("folder/${file.lastPathSegment}")
uploadTask = riversRef.putFile(file)

// Register observers to listen for when the download is done or if it fails
uploadTask.addOnFailureListener {
// Handle unsuccessful uploads
}.addOnSuccessListener {
// taskSnapshot.metadata contains file metadata such as size, content-type, etc.
// ...
}