Realtime Database, Authentication
//read and write - shallower rules override deeper rules
//validate - rules don't cascade, must all evaluate to true to write
- Rule types = ".read", ".write", ".validate"
- Grant write access to "/users/<uid>/"
".write": "$uid === auth.uid"
https://firebase.google.com/docs/reference/security/database/#variables
//before starting, change security rules so that read + write are both true
//when structuring data, flatten data structures instead of nesting them + duplicate for 2 way relationship
//when passing objects, default + custom constructor required
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference();
DatabaseReference refChild = ref.child("posts");
- WRITE TO THE DATABASE
ref.child("posts").setValue("I can only add one value to branch!");
refChild.push().setValue(Post1);
refChild.push().setValue(Post2);
refChild.push().setValue(Post3);
- REMOVE FROM DATABASE
refChild.removeValue();
- READ FROM DATABASE IN REALTIME
refChild.addValueEventListener(new ValueEventListener() {
//use addListenerForSingleValueEvent to only read once
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
String data = dataSnapshot.getValue(String.class);
}
@Override
public void onCancelled(DatabaseError databaseError) { }
});
- READING ALL VALUES IN SPECIFIC JSON TREE
//add to onDataChange
for (DataSnapshot messageSnapshot : dataSnapshot.getChildren()) {
String name = (String) messageSnapshot.getValue();
}
//getting values of multiple objects, will loop for all objects in branch
for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
//make sure to use "Object" instead of "Post"
Map<String, Object> post = (Map<String, Object>) postSnapshot.getValue();
String author = post.get("author").toString();
String content = post.get("content").toString();
String starCount = post.get("starCount").toString();
}
- READING A CHILD BRANCH THAT IS ADDED/CHANGED/REMOVED
//triggered once for each existing child, and then every time child added, blog posts
refChild.addChildEventListener(new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) { }
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) { }
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) { }
});
- UPDATING AT THE SAME TIME FOR 2-WAY RELATIONSHIPS
//add following to object class
public Map<String, Object> toMap() {
HashMap<String, Object> result = new HashMap<>();
result.put("content", content);
result.put("author", author);
result.put("size", size);
return result;
}
//add following to main class
Post post = new Post("Hello", "Ishan", 10);
String key = refChild.push().getKey();
Map<String, Object> postValues = post.toMap();
Map<String, Object> childUpdates = new HashMap<>();
childUpdates.put("/posts/" + key, postValues);
childUpdates.put("/user-posts/" + post.getAuthor(), key);
ref.updateChildren(childUpdates);
- SORT DATA IN ASCENDING ORDER
Query sorted = refChild.orderByChild("starCount");
//can also orderByKey on a specific branch
sorted.addChildEventListener(new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Map<String, Object> hash = (Map<String, Object>) dataSnapshot.getValue();
//each hash represents a separate post
String author = hash.get("author").toString();
String content = hash.get("content").toString();
String starCount = hash.get("starCount").toString();
Log.d("map", author + ", " + content + ", " + starCount);
}
});
- OFFLINE BEHAVIOR
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
ref.keepSynced(true);
DatabaseReference connected = database.getReference((".info/connected"));
connected.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot snapshot) {
boolean connected = snapshot.getValue(Boolean.class);
if (connected)
Log.d("connection", "yes");
else
Log.d("connection", "no");
}
});
1. Firebase Console -> Create a project -> Add Firebase to your Android app
2. Download google-services.JSON and add to "app directory"
3. Add dependencies to project gradle - "classpath 'com.google.gms:google-services:3.0.0'"
4. Add to bottom of app gradle - "apply plugin: 'com.google.gms.google-services'"
ADD DEPENDENCIES IN APP GRADLE FOR WHATEVER FIREBASE FEAUTURES YOU WISH TO USE (ANALYTICS, REALTIME DATABASE, ETC)
- surprisingly, don't need internet permissions
//NoSuchMethodError -> use same Firebase library versions
//StorageException -> use more specific StorageReference and use ".jpg" + edit permission rules on console
- STORE IMAGE FROM GALLERY/CAMERA
final int GALLERY_REQUEST_CODE = 1;
final int CAMERA_REQUEST_CODE = 2;
FirebaseStorage storage = FirebaseStorage.getInstance();
StorageReference storageRef = storage.getReferenceFromUrl("gs://test-caae7.appspot.com");
UploadTask uploadTask;
final Intent galleryIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
final Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
galleryButton.setOnClickListener((view) {
startActivityForResult(galleryIntent, 1);
});
cameraButton.setOnClickListener((view) {
startActivityForResult(cameraIntent, 2);
});
//generate method
protected void onActivityResult {
String name = "test";
StorageReference picRef = storageRef.child("images/" + name + ".jpg");
//surround with try catch
switch (requestCode) {
case GALLERY_REQUEST_CODE: {
Uri path = data.getData();
StorageMetadata metadata = new StorageMetadata.Builder().setContentType("image/jpg").build();
uploadTask = picRef.putFile(path, metadata);
break;
}
case CAMERA_REQUEST_CODE: {
Bitmap pictureObject = (Bitmap) data.getExtras().get("data");
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
pictureObject.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
byte[] byteArray = outputStream.toByteArray();
StorageMetadata metadata = new StorageMetadata.Builder().setContentType("image/jpg").build();
uploadTask = picRef.putBytes(byteArray, metadata);
break;
}
}
uploadTask.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) { }
}).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
@Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
Uri downloadUrl = taskSnapshot.getDownloadUrl();
}
});
}
- MONITOR + MODIFY UPLOAD PROGRESS
uploadTask.pause();
uploadTask.resume();
uploadTask.cancel();
uploadTask.addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
@Override
public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
double total = taskSnapshot.getTotalByteCount();
double current = taskSnapshot.getBytesTransferred();
double progress = (100.0 * (current/total));
}
}).addOnPausedListener(new OnPausedListener<UploadTask.TaskSnapshot>() {
@Override
public void onPaused(UploadTask.TaskSnapshot taskSnapshot) { }
});
- DOWNLOAD A FILE BYTE[]
//ten megabytes
long maxSize = 1024 * 1024 * 10;
picRef.getBytes(maxSize).addOnSuccessListener(new OnSuccessListener<byte[]>() {
@Override
public void onSuccess(byte[] bytes) {
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
imageView.setImageBitmap(bitmap);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) { }
});
- DELETE A FILE
picRef.delete().addOnSuccessListener(new OnSuccessListener() {
@Override
public void onSuccess(Void aVoid) { }
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception exception) { }
});
//enable sign-in providers in Firebase Console -> Sign-In Method
//for creating account + signing in, must put code in separate method
- CREATE AN ACCOUNT WITH EMAIL/PASSWORD
final FirebaseAuth auth = FirebaseAuth.getInstance();
//password minimum 8 characters
auth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (!task.isSuccessful()) { }
}
});
- SIGN IN WITH EMAIL/PASSWORD
//if login does not occur, update Google Play Services on device
final FirebaseAuth auth = FirebaseAuth.getInstance();
auth.signInWithEmailAndPassword(email, password)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (!task.isSuccessful())
Log.d("Error", "Not successful");
else
Log.d("Message", "Successful");
}
});
- CHECK SIGN-IN STATE
FirebaseAuth.AuthStateListener listener;
listener = new FirebaseAuth.AuthStateListener() {
@Override
public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
//user is signed in
if (user != null)
//user is not signed in
else
}
};
OnStart() -> auth.addAuthStateListener(listener);
onStop() -> if (listener != null)
auth.removeAuthStateListener(listener);
- SIGN OUT USER
FirebaseAuth.getInstance().signOut();
- GET USER PROFILE FOR FIREBASE ACCOUNT
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user != null) {
String name = user.getDisplayName();
String email = user.getEmail();
Uri photoUrl = user.getPhotoUrl();
String uid = user.getUid();
}
- SIGN IN WITH FACEBOOK
1. Go to Facebook Developers site + create app, follow "Get Started" guide
2. Add Gradle dependencies, App ID to strings.xml, meta-data to manifest, internet permissions
3. Add "FacebookSdk.sdkInitialize(getApplicationContext());" before setContentView()
4. Enable Facebook sign-in on Firebase and add enter App ID/App Secret
5. Within Facebook console, add product -> Facebook login -> link from Firebase
6. Add "com.facebook.login.widget.LoginButton" to layout file
public CallbackManager callback = CallbackManager.Factory.create();
public FirebaseAuth auth = FirebaseAuth.getInstance();
LoginButton loginButton = (LoginButton) findViewById(R.id.login_button);
loginButton.setReadPermissions("email", "public_profile");
loginButton.registerCallback(callback, new FacebookCallback<LoginResult>() {
@Override
public void onSuccess(LoginResult loginResult) {
Log.d("message", "facebook:onSuccess:" + loginResult);
handleFacebookAccessToken(loginResult.getAccessToken());
}
@Override
public void onCancel() { }
@Override
public void onError(FacebookException error) { }
});
onActivityResult() -> callback.onActivityResult(requestCode, resultCode, data);
private void handleFacebookAccessToken(AccessToken token) {
AuthCredential credential = FacebookAuthProvider.getCredential(token.getToken());
auth.signInWithCredential(credential).addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
Log.d("login", "signInWithCredential:onComplete:" + task.isSuccessful());
if (!task.isSuccessful())
Log.w("login", "signInWithCredential", task.getException());
}
});
}
Incorrect hash -> http://stackoverflow.com/questions/16767672/key-hash-doesnt-match-while-facebook-login-in-android
- GET USER PROFILE FOR FACEBOOK/GOOGLE ACCOUNT
FirebaseUser user = auth.getCurrentUser();
if (user != null) {
for (UserInfo profile : user.getProviderData()) {
String providerID = profile.getProviderId();
String providerUID = profile.getUid();
String name = profile.getDisplayName();
Uri photoURL = profile.getPhotoUrl();
String userID = user.getUid();
String email = user.getEmail();
}
}
FIREBASE API