WebViewの実装について

# WebViewとは

[参考にした記事](https://qiita.com/kamimi01/items/b4d6cbafa587831c1be0 "参考にした記事")

# WebView.swift
```
import SwiftUI
import WebKit

struct WebView: UIViewRepresentable {
    let url: String
    
    func makeUIView(context: Context) -> WKWebView {
        return WKWebView()
    }
    
    func updateUIView(_ uiView: WKWebView, context: Context) {
        guard let url = URL(string: url) else {
            return
        }
        let request = URLRequest(url: url)
        uiView.load(request)
    }
}


```
# ContentView.swift
※コード全体の仕組みとしてはGoogleのログインが出来たらアカウントの情報やアイコンと一緒にWebViewも表示されるようになっています。
```
import SwiftUI
import Firebase
import FirebaseAuth
import GoogleSignIn

struct ContentView: View {
    private let url = "https://www.apple.com"
    
    @State private var isSignedIn = false
    @State private var userName: String = ""
    @State private var userEmail: String = ""
    @State private var profileImage: UIImage? = nil

    var body: some View {
        VStack(spacing: 20) {
            //MARK: -  ログイン後
            if isSignedIn {
                VStack {
                    if let profileImage = profileImage {
                        Image(uiImage: profileImage)
                            .resizable()
                            .aspectRatio(contentMode: .fit)
                            .frame(width: 100, height: 100)
                            .clipShape(Circle())
                            .overlay(Circle().stroke(Color.blue, lineWidth: 2))
                            .shadow(radius: 5)
                    }

                    Text("Welcome, \(userName)")
                        .font(.title2)
                        .bold()

                    Text(userEmail)
                        .font(.subheadline)
                        .foregroundColor(.gray)

                    Button("Sign Out") {
                        signOut()
                    }
                    .frame(width: 200, height: 50)
                    .background(Color.red)
                    .foregroundColor(.white)
                    .cornerRadius(10)
                    
                    WebView(url: url)//ログイン成功したらWebViewが表示される
                }
            } else {
                VStack {
                    GoogleSignInButton {
                        signInWithGoogle()
                    }
                }
            }
        }
        .padding()
        .onAppear {
            restoreSession()
        }
    }

    private func signInWithGoogle() {
        guard let clientID = FirebaseApp.app()?.options.clientID else { return }

        let config = GIDConfiguration(clientID: clientID)
        guard let rootViewController = UIApplication.shared.connectedScenes
            .compactMap({ $0 as? UIWindowScene })
            .flatMap({ $0.windows })
            .first(where: { $0.isKeyWindow })?.rootViewController else {
            print("Unable to get root view controller.")
            return
        }

        GIDSignIn.sharedInstance.signIn(withPresenting: rootViewController) { result, error in
            if let error = error {
                print("Google Sign-In failed: \(error.localizedDescription)")
                return
            }

            guard let user = result?.user,
                  let idToken = user.idToken?.tokenString else { return }

            let credential = GoogleAuthProvider.credential(withIDToken: idToken, accessToken: user.accessToken.tokenString)
            Auth.auth().signIn(with: credential) { authResult, error in
                if let error = error {
                    print("Firebase Authentication failed: \(error.localizedDescription)")
                } else {
                    self.isSignedIn = true
                    self.userName = user.profile?.name ?? "No Name"
                    self.userEmail = user.profile?.email ?? "No Email"
                    
                    // Load profile image
                    if let imageURL = user.profile?.imageURL(withDimension: 200) {
                        loadProfileImage(from: imageURL)
                        saveSession(userName: self.userName, userEmail: self.userEmail, profileImageURL: imageURL)
                    }
                }
            }
        }
    }

    private func signOut() {
        do {
            try Auth.auth().signOut()
            GIDSignIn.sharedInstance.signOut()
            clearSession()
            self.isSignedIn = false
            self.userName = ""
            self.userEmail = ""
            self.profileImage = nil
        } catch {
            print("Failed to sign out: \(error.localizedDescription)")
        }
    }

    private func loadProfileImage(from url: URL) {
        URLSession.shared.dataTask(with: url) { data, _, error in
            if let error = error {
                print("Failed to load profile image: \(error.localizedDescription)")
                return
            }

            if let data = data, let image = UIImage(data: data) {
                DispatchQueue.main.async {
                    self.profileImage = image
                }
            }
        }.resume()
    }

    // MARK: - Session Management
    private func saveSession(userName: String, userEmail: String, profileImageURL: URL) {
        UserDefaults.standard.setValue(userName, forKey: "userName")
        UserDefaults.standard.setValue(userEmail, forKey: "userEmail")
        UserDefaults.standard.setValue(profileImageURL.absoluteString, forKey: "profileImageURL")
        UserDefaults.standard.setValue(true, forKey: "isSignedIn")
    }

    private func restoreSession() {
        let defaults = UserDefaults.standard
        if defaults.bool(forKey: "isSignedIn") {
            self.isSignedIn = true
            self.userName = defaults.string(forKey: "userName") ?? ""
            self.userEmail = defaults.string(forKey: "userEmail") ?? ""
            
            if let imageURLString = defaults.string(forKey: "profileImageURL"),
               let imageURL = URL(string: imageURLString) {
                loadProfileImage(from: imageURL)
            }
        }
    }

    private func clearSession() {
        let defaults = UserDefaults.standard
        defaults.removeObject(forKey: "userName")
        defaults.removeObject(forKey: "userEmail")
        defaults.removeObject(forKey: "profileImageURL")
        defaults.setValue(false, forKey: "isSignedIn")
    }
}

// MARK: - Google Sign-In Button
struct GoogleSignInButton: View {
    let action: () -> Void

    var body: some View {
        Button(action: action) {
            HStack {
                Image(systemName: "g.circle.fill")
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(width: 30, height: 30)
                    .foregroundColor(.white)

                Text("Sign in with Google")
                    .fontWeight(.semibold)
                    .font(.system(size: 18))
            }
            .frame(width: 250, height: 50)
            .background(Color.blue)
            .foregroundColor(.white)
            .cornerRadius(25)
        }
        .shadow(radius: 5)
    }
}

#Preview {
    ContentView()
}

```
# WebViewを使用している箇所
if let profileImage = profileImage{ } の内部となっています
```
                VStack {
                    if let profileImage = profileImage {
                        Image(uiImage: profileImage)
                            .resizable()
                            .aspectRatio(contentMode: .fit)
                            .frame(width: 100, height: 100)
                            .clipShape(Circle())
                            .overlay(Circle().stroke(Color.blue, lineWidth: 2))
                            .shadow(radius: 5)
                    }

                    Text("Welcome, \(userName)")
                        .font(.title2)
                        .bold()

                    Text(userEmail)
                        .font(.subheadline)
                        .foregroundColor(.gray)

                    Button("Sign Out") {
                        signOut()
                    }
                    .frame(width: 200, height: 50)
                    .background(Color.red)
                    .foregroundColor(.white)
                    .cornerRadius(10)
                    
                    WebView(url: url)//ログイン成功したらWebViewが表示される
                }
```

# Googleのログインボタンを作成しているコード
```
// MARK: - Google Sign-In Button
struct GoogleSignInButton: View {
    let action: () -> Void

    var body: some View {
        Button(action: action) {
            HStack {
                Image(systemName: "g.circle.fill")
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(width: 30, height: 30)
                    .foregroundColor(.white)

                Text("Sign in with Google")
                    .fontWeight(.semibold)
                    .font(.system(size: 18))
            }
            .frame(width: 250, height: 50)
            .background(Color.blue)
            .foregroundColor(.white)
            .cornerRadius(25)
        }
        .shadow(radius: 5)
    }
}
```