我试过很多次跟随不同的视频讲述如何将个人资料照片上传到Firebase,目前,Auth可以工作,并创建一个具有全名、UID和密码的用户,但Firestore数据库中没有存储图像URL,Firestore存储中也没有存储实际图像。
当用户点击“注册”,我希望帐户被创建,以及图像被存储。
Firebase存储规则:
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if
request.auth != null;
}
}
}
创建帐户验证视图:
import SwiftUI
struct CreateAccountAuth: View {
@State private var email = ""
@State private var password = ""
@State private var fullname = ""
@Environment(\.presentationMode) var presentationMode
@EnvironmentObject var viewModel: AuthViewModel
@State private var showImagePicker = false
@State private var selectedImage: UIImage?
@State private var profileImage: Image?
var body: some View {
VStack(alignment: .leading) {
Text("Let's get started")
.font(.title)
.fontWeight(.semibold)
Button {
showImagePicker.toggle()
} label: {
if let profileImage = profileImage {
profileImage
.resizable()
.scaledToFill()
.frame(width: 100, height: 100)
.cornerRadius(10)
} else {
Image("EmptyProfile")
.resizable()
.scaledToFill()
.frame(width: 100, height: 100)
}
}
.padding(.bottom, 24)
.fullScreenCover(
isPresented: $showImagePicker,
onDismiss: loadImage) {
ImagePicker(image: $selectedImage)
}
VStack (alignment:.leading) {
CustomInputField(imageName: "person", placeholderText: "Name", text: $fullname)
.padding(.bottom, 24)
CustomInputField(imageName: "mail", placeholderText: "Email", text: $email)
.padding(.bottom, 24)
CustomInputField(
imageName: "lock",
placeholderText: "Password",
isSecureField: true,
text: $password)
}.padding(.bottom, 16)
VStack {
Button {
viewModel.register(
withEmail: email,
password: password,
fullname: fullname)
} label: {
Text("Sign Up")
.font(.headline)
.foregroundColor(.white)
.frame(height: 50)
.frame(maxWidth: .infinity)
.background(Color.accentColor)
.clipShape(Capsule())
.padding(.vertical)
}
Text("or")
Button {
print("Continue with phone..")
} label: {
Text("Sign up with phone")
.font(.headline)
.fontWeight(.regular)
.foregroundColor(.black)
.frame(height: 50)
.frame(maxWidth: .infinity)
.background(Color(.systemGray5))
.clipShape(Capsule())
.padding(.vertical)
}
Spacer()
Button {
presentationMode.wrappedValue.dismiss()
} label: {
HStack {
Text("Already have an account?")
.font(.footnote)
Text("Sign in")
.font(.footnote)
.fontWeight(.semibold)
}
}
.padding(.bottom, 40)
}
.padding(.top, 56)
}
.padding(.top, 40)
.navigationBarHidden(true)
.padding(.leading)
.padding(.trailing)
}
func loadImage() {
guard let selectedImage = selectedImage else { return }
profileImage = Image(uiImage: selectedImage)
}
}
struct CreateAccountAuth_Previews: PreviewProvider {
static var previews: some View {
CreateAccountAuth()
}
}
验证视图模型视图:
import SwiftUI
import FirebaseAuth
import FirebaseCore
import FirebaseStorage
import FirebaseFirestore
import FirebaseFirestoreSwift
class AuthViewModel: ObservableObject {
@Published var userSession: User?
@Published var didAuthenticateUser = false
private var tempUserSession: User?
init() {
self.userSession = Auth.auth().currentUser
print("DEBUG: User session is \(self.userSession?.uid)")
}
func login(withEmail email: String, password: String) {
Auth.auth().signIn(withEmail: email, password: password) { result, error in if let error = error {
print("DEBUG: Failed to register with error \(error.localizedDescription)")
return
}
guard let user = result?.user else { return }
self.userSession = user
print("DEBUG: Did log user in...")
}
}
func register(withEmail email: String, password: String, fullname: String) {
Auth.auth().createUser(withEmail: email, password: password) { result, error in
if let error = error {
print("DEBUG: Failed to register with error \(error.localizedDescription)")
return
}
guard let user = result?.user else { return }
self.tempUserSession = user
print("DEBUG: Registered user successfully")
print("DEBUG: User is \(self.userSession)")
let data = ["email": email,
"fullname": fullname,
"uid": user.uid]
Firestore.firestore().collection("users")
.document(user.uid)
.setData(data) { _ in
self.didAuthenticateUser = true
}
}
}
func signOut() {
//sets user session to nil so we show login view
userSession = nil
tempUserSession = nil
didAuthenticateUser = false
//signs user out on server(backend)
try? Auth.auth().signOut()
}
func uploadProfileImage(_ image: UIImage) {
guard let uid = tempUserSession?.uid else { return }
ImageUploader.uploadImage(image: image) { profileImageUrl in
Firestore.firestore().collection("users")
.document(uid)
.updateData(["profileImageUrl": profileImageUrl]) { _ in
self.userSession = self.tempUserSession
}
}
}
}
图像上传器:
import Firebase
import UIKit
import FirebaseStorage
struct ImageUploader {
static func uploadImage(image: UIImage, completion: @escaping(String) -> Void) {
guard let imageData = image.jpegData(compressionQuality: 0.5) else { return }
let filename = NSUUID().uuidString
let ref = Storage.storage().reference(withPath: "/profile_image/\(filename)")
ref.putData(imageData, metadata: nil) { _, error in
if let error = error {
print("DEBUG: Failed to upload image with error: \(error.localizedDescription)")
return
}
ref.downloadURL { imageUrl, _ in
guard let imageUrl = imageUrl?.absoluteString else { return }
completion(imageUrl)
}
}
}
}
1条答案
按热度按时间r1wp621o1#
问题是您没有调用 AuthViewModel 中的 uploadProfileImage 函数。
为了调用它并传递选中的图像,需要在视图模型中保持图像状态,或者在视图中调用函数,在视图中调用函数需要在register函数中完成闭包,以便等待用户创建完成,这样会比较乱,建议将图像移到视图模型中。
您需要更改 ImagePicker。
还有 loadImage 函数。