Firebase Offline: Simplify Development with Firebase Local Emulator Suite (iOS/Android/Web)
Are you a developer who relies on Firebase for building powerful apps?
If so, you’ll be happy to discover Firebase Local Emulator Suite — a game-changing tool that lets you use the power of Firebase locally. By using Firebase services locally, you can supercharge your development process, boost efficiency, and cut down costs.
Let’s dive deeper into how Firebase Local Emulator Suite can help your development workflow.
Part 1: Setting up the Firebase Emulator UI
- Installing Firebase Local Emulator Suite:
To begin, let’s install Firebase CLI on your system. Open your terminal or command prompt and execute the following command:
npm install -g firebase-tools
I am using npm but you can use the standalone library if needed.
2. Signing in to Firebase CLI: To sign in to Firebase CLI, open your terminal or command prompt and enter the following command:
firebase login
This command launches a web browser window, prompting you to sign in to your Google account associated with Firebase.
- Authentication Process: In the web browser window that opens, enter your Google account credentials if you are not already signed in. If you are already signed in to a Google account, It will just print out your email to the console.
- Granting Permissions: After logging in, Firebase will request permission to access your Google account and manage your Firebase projects. To proceed, click “Allow” to grant these permissions. This step is crucial for Firebase CLI to interact with your Firebase projects effectively.
- Verifying Authentication: Once permissions are granted, return to your terminal or command prompt. You should see a message indicating successful authentication with Firebase CLI. This confirmation ensures that Firebase CLI has established a secure connection with your Firebase account.
3. Initializing Firebase Project:
To begin, navigate to your project directory using the terminal or command prompt. Create a new folder for your project if one does not already exist. Once inside your project directory, choose the following feature to initialize Firebase by using the arrow keys and press the space bar to make a selection.
4. Now let’s create our new firebase project:
Choose to Create a new Project Specify the name of your project and hit ‘Return/Enter’
Firebase CLI will prompt you to select Firebase features and emulators to set up for your project. Choose the following options:
- Authentication Emulator
- Firestore Emulator
- Storage Emulator
select all the default ports and download the emulator.
5. Before running Firebase Emulator to replicate Firebase services locally, ensure you have Java installed on your system. Follow these steps to set up Java and seamlessly configure Firebase Emulators for your project.
If you have Windows OS you can install Java by visiting: https://www.java.com/en/ and configure it.
MacOS/Linux Users use this command to install Java in your system and configure it. (If you don’t have Brew installed on your system install it by visiting this site. https://brew.sh/ )
brew install --cask adoptopenjdk
After that run this command to make sure Java has been installed successfully.
java -version
6. After that visit https://console.firebase.google.com/ select your project and create a storage bucket for your project.
7. After that run the firebase init command again and select Storage Configure a security rules file for Cloud Storage and hit ‘Return/Enter’.
8. Finally, run the Firebase emulator by using this command
firebase emulators:start
Now visit: http://127.0.0.1:4000/ to access our Firebase emulator UI.
Part 2: Connecting it with our apps (iOS, Android & Web)
1. iOS
- Create a new SwiftUI Project.
- create a new iOS app in your Firebase console.
- Register your app with your bundle ID
- Download the GoogleService-Info.plist file and add it to your iOS App.
- Now let’s add the Firebase SDK to our iOS app.
- Select Add Package Dependencies
- paste this URL: https://github.com/firebase/firebase-ios-sdk in the search bar and follow these steps to add Firebase SDK to your iOS app.
- Great! we are done with the Firebase SDK installation. Now we have to configure it. So that we can use it to perform firebase operations.
- Now let’s add the configuration code. Import FirebaseCore and FirebaseAuth.
- After that if you are getting an error “No Such Module ‘FirebaseAuth”.
- Then, Add the FirebaseAuth framework to your project.
- Inside “FirebaseLocalEmulatorApp.swift” File paste the following code.
import SwiftUI
import FirebaseCore
import FirebaseAuth
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
FirebaseApp.configure()
Auth.auth()
.useEmulator(withHost: "localhost", port: 9099) // configure FirebaseAuth
return true
}
}@main
struct FirebaseLocalEmulatorApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
- Now let’s add a launch argument to our app so that we can use our Firebase local emulator.
- Click on the app name and select the Edit Scheme…
- And add ‘-useEmulator YES’ flag to your arguments.
Finally, The FirebaseAuth config is completed. Now let’s perform a simple Signup process.
- Create two states for storing the user’s email and password.
@State private var email: String = ""
@State private var password: String = ""
- Create Textfield for email, SecureField for password, and a button for submitting the form.
import SwiftUI
struct ContentView: View {
@State private var email: String = ""
@State private var password: String = ""
var body: some View {
VStack(spacing: 0) {
Spacer()
TextField("Email", text: $email)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding(12)
SecureField("Password", text: $password)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding(12) Button(action: {
}) {
Text("Signup")
.frame(maxWidth: .infinity)
.padding(12)
.foregroundColor(.white)
.background(Color.blue)
.cornerRadius(12)
}
.padding()
Spacer()
}
.padding()
}
}#Preview {
ContentView()
}
- Now, let’s implement the signup process when the button is clicked by adding the FirebaseAuth signup function.
import FirebaseAuth
func signUp() {
Auth.auth().createUser(withEmail: email, password: password) { result, error in
if((error == nil)) {
print(result!.user.email!)
} else {
print(error!.localizedDescription)
}
}
}
Button(action: {
signUp()
}) {
Text("Signup")
.frame(maxWidth: .infinity)
.padding(12)
.foregroundColor(.white)
.background(Color.blue)
.cornerRadius(12)
}
.padding()
Spacer()
}
That’s it! now let’s perform the signup process by clicking the button.
- Finally, check our Firebase local emulator’s Authentication section.
For Firebase Firestore configuration, please use the following code and add FirebaseFirestoreSwiftframework.
import SwiftUI
import FirebaseCore
import FirebaseAuth
import FirebaseFirestore
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
FirebaseApp.configure()
// Firestore Configuration
let settings = Firestore.firestore().settings
settings.host = "127.0.0.1:8080"
settings.cacheSettings = MemoryCacheSettings()
settings.isSSLEnabled = false
Firestore.firestore().settings = settings
// Firebase Auth configuration
Auth.auth().useEmulator(withHost: "localhost", port: 9099)
return true
}
}@main
struct FirebaseLocalEmulatorApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
2. Android
- Create a new Android Jetpack Compose Project.
- After that Create a new app in your Firebase console.
- Register your app, download the google-services.json, and add it your to your module (app-level) root directory.
- After that, follow all the steps to connect Firebase with your app.
- Add Firebase Auth SDK to your project.
- Create a new XML file network configuration ‘network_security_config.xml’ and paste the following code.
<?xml version=”1.0" encoding=”utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted=”true” />
</network-security-config>
- Now go to MainActivity File. Add Firebase auth configuration and add two states for storing email and password.
class MainActivity : ComponentActivity() {
private lateinit var auth: FirebaseAuth;
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Firebase Auth Configuration
auth = Firebase.auth
auth.useEmulator("10.0.2.2", 9099)
var email by remember { mutableStateOf(TextFieldValue()) }
var password by remember { mutableStateOf(TextFieldValue()) }
- create two text fields for email and password input with a button.
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
OutlinedTextField(
value = email,
onValueChange = { email = it },
label = { Text("Email") },
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp)
)
OutlinedTextField(
value = password,
onValueChange = { password = it },
label = { Text("Password") },
visualTransformation = PasswordVisualTransformation(),
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp)
) Button(
onClick = {
signup()
},
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp)
) {
Text("Signup")
}
}
- Add a signup function to perform the signup process.
fun signup() {
val firebaseUser = auth.createUserWithEmailAndPassword(email.text, password.text).addOnCompleteListener {
result ->
if(result.result.user?.email != null) {
Log.d("Firebase", result.result.user?.email!!)
} else {
Log.d("Firebase", result.exception?.localizedMessage!!)
}
}
}
MainActivity.kt
package com.example.firebaselocalemulator
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.example.firebaselocalemulator.ui.theme.FirebaseLocalEmulatorTheme
import com.google.firebase.Firebase
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.auth
class MainActivity : ComponentActivity() {
private lateinit var auth: FirebaseAuth; override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Firebase Auth Configuration
auth = Firebase.auth
auth.useEmulator("10.0.2.2", 9099)
setContent {
var email by remember { mutableStateOf(TextFieldValue()) }
var password by remember { mutableStateOf(TextFieldValue()) }
fun signup() {
val firebaseUser = auth.createUserWithEmailAndPassword(email.text, password.text).addOnCompleteListener {
result ->
if(result.result.user?.email != null) {
Log.d("Firebase", result.result.user?.email!!)
} else {
Log.d("Firebase", result.exception?.localizedMessage!!)
}
}
}
FirebaseLocalEmulatorTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
OutlinedTextField(
value = email,
onValueChange = { email = it },
label = { Text("Email") },
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp)
) OutlinedTextField(
value = password,
onValueChange = { password = it },
label = { Text("Password") },
visualTransformation = PasswordVisualTransformation(),
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp)
) Button(
onClick = {
signup()
},
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp)
) {
Text("Signup")
}
}
}
}
}
}
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
FirebaseLocalEmulatorTheme { }
}
Now, Let’s perform the signup process.
Finally, navigate to the Authentication section of the Firebase Local Emulator and refresh the list. You will see that our new user has been added successfully.
For Firebase Firestore configuration, please use the following code and add FirebaseFirestore SDK.
package com.example.firebaselocalemulator
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.example.firebaselocalemulator.ui.theme.FirebaseLocalEmulatorTheme
import com.google.firebase.Firebase
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.auth
import com.google.firebase.firestore.firestore
import com.google.firebase.firestore.firestoreSettings
class MainActivity : ComponentActivity() {
private lateinit var auth: FirebaseAuth;
val db = Firebase.firestore override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Firebase Auth Configuration
auth = Firebase.auth
auth.useEmulator("10.0.2.2", 9099)
db.useEmulator("10.0.2.2", 8080) db.firestoreSettings = firestoreSettings {
isPersistenceEnabled = false
}
setContent {
var email by remember { mutableStateOf(TextFieldValue()) }
var password by remember { mutableStateOf(TextFieldValue()) }
fun signup() {
val firebaseUser = auth.createUserWithEmailAndPassword(email.text, password.text).addOnCompleteListener {
result ->
if(result.result.user?.email != null) {
Log.d("Firebase", result.result.user?.email!!)
} else {
Log.d("Firebase", result.exception?.localizedMessage!!)
}
}
}
FirebaseLocalEmulatorTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
OutlinedTextField(
value = email,
onValueChange = { email = it },
label = { Text("Email") },
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp)
) OutlinedTextField(
value = password,
onValueChange = { password = it },
label = { Text("Password") },
visualTransformation = PasswordVisualTransformation(),
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp)
) Button(
onClick = {
signup()
},
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp)
) {
Text("Signup")
}
}
}
}
}
}
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
FirebaseLocalEmulatorTheme { }
}
3. Web
- Create a new react project by using the following command.
npx create-react-app firebaselocalemulator
- open it in your favorite code editor.
- change the directory and run the react app.
cd firebaselocalemulator && npm start
- Add Firebase SDK.
App.js file
- import getAuth and connectAuthEmulator functions from “firebase/auth”
import { getAuth, connectAuthEmulator } from "firebase/auth";
- Add firebase auth instance.
const app = initializeApp(firebaseConfig);
const auth = getAuth();
connectAuthEmulator(auth, "http://127.0.0.1:9099");
- Create two states for storing email and password.
const [email, setEmail] = useState();
const [password, setPassword] = useState();
- create two input fields for email and password with a button for submitting the form.
function App() {
const [email, setEmail] = useState();
const [password, setPassword] = useState();
return (
<div className="App" style={{
height: '100vh',
display: 'flex',
justifyContent:'center',
alignItems:'center',
gap: '12px',
flexDirection: 'column'
}}>
<input type="text" defaultValue={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email"/>
<input type="password" defaultValue={password} onChange={(e) => setPassword(e.target.value)} placeholder="Password"/>
<input type="button" value="Submit"/>
</div>
);
}
- Import createUserWithEmailAndPassword from “firebase/auth” and pass the auth instance.
import { getAuth, connectAuthEmulator, createUserWithEmailAndPassword } from “firebase/auth”;
const signup = () => {
createUserWithEmailAndPassword(auth, email, password)
.then((data) => {
console.log(data.user?.email)
}).catch(e => console.log(e))
}
App.js
import './App.css';
import {useState} from 'react';
import { initializeApp } from "firebase/app";
import { getAuth, connectAuthEmulator, createUserWithEmailAndPassword } from "firebase/auth";
// Your web app's Firebase configuration
const firebaseConfig = {
apiKey: "-lY",
authDomain: "firebaseapp.com",
projectId: "firebaselocalsuite",
storageBucket: "firebaselocalsuite.appspot.com",
messagingSenderId: "1234",
appId: ""
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
const auth = getAuth();
connectAuthEmulator(auth, "http://127.0.0.1:9099");
function App() {
const [email, setEmail] = useState();
const [password, setPassword] = useState();
const signup = () => {
createUserWithEmailAndPassword(auth, email, password)
.then((data) => {
console.log(data.user?.email)
}).catch(e => console.log(e))
}
return (
<div className="App" style={{
height: '100vh',
display: 'flex',
justifyContent:'center',
alignItems:'center',
gap: '12px',
flexDirection: 'column'
}}>
<input type="text" defaultValue={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email"/>
<input type="password" defaultValue={password} onChange={(e) => setPassword(e.target.value)} placeholder="Password"/>
<input type="button" onClick={() => signup()} value="Submit"/>
</div>
);
}export default App;
- Finally, navigate to the Authentication section of the Firebase Local Emulator and refresh the list. You will see that our new user has been added successfully.
For Firebase Firestore configuration, please use the following code and import getFirestore from “firebase/auth”
import { getAuth, connectAuthEmulator, createUserWithEmailAndPassword, getFirestore } from "firebase/auth";
const db = getFirestore();
connectFirestoreEmulator(db, '127.0.0.1', 8080);
Thank you. Don’t forget to clap 👏 if you like this article. 🤩
Useful Links:
Final Code- https://github.com/M4yankChoudhary/Firebase-Local-Emulator-Suite
Linkedin- https://www.linkedin.com/in/mayank--choudhary/
Website- https://mayankchoudhary.com