Hoping I have an simple answer to a mistake I'm making getting my images download URL. This was working, but stopped after fixing many other compile issues, some related to Gradle Implementation versions. Clearly an indication that I can't understand Firebase StorageReference coding documentation. I don't find most programmers know how to document for dummies :).
I also have a security question after related to best practice from some information I read. Thanks for any answers you can provide.
So here is my App Gradle file:
//////////////////////////////////
apply plugin: 'com.android.application'
android {
compileSdkVersion versions.compileSdk
buildToolsVersion versions.buildTools
defaultConfig {
applicationId "com.example.cell.der"
//////////////////////////////////////////////////////////////////////////////////////////////////
// The manifest setting tells Google Play that your application can be installed on
// devices with Android 4.0 (API level 14) and higher. If you are using Gradle build files,
// the minSdkVersion setting in the build file overrides the manifest settings:
// <uses-sdk
// android:minSdkVersion="14"
// android:targetSdkVersion="23" />
//////////////////////////////////////////////////////////////////////////////////////////////////
minSdkVersion 14
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
multiDexEnabled true
}
buildTypes {
release {
shrinkResources true // This must be first
minifyEnabled true // This must be after shrinkResources
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
customDebug {
debuggable true
}
debug {
testCoverageEnabled = false
}
}
}
repositories {
google()
jcenter()
mavenCentral()
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support:animated-vector-drawable:27.1.1'
implementation 'com.android.support:recyclerview-v7:27.1.1'
implementation 'com.android.support:exifinterface:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.android.support:design:27.1.1'
implementation 'com.android.support:cardview-v7:27.1.1'
implementation 'com.android.support:support-v4:27.1.1'
implementation 'com.android.support:support-annotations:27.1.1'
implementation "com.android.support:support-fragment:27.1.1"
implementation 'com.google.firebase:firebase-core:16.0.0'
implementation 'com.google.firebase:firebase-auth:16.0.1'
implementation 'com.google.firebase:firebase-storage:16.0.1'
implementation 'com.google.firebase:firebase-database:16.0.1'
implementation "com.google.firebase:firebase-firestore:17.0.1"
implementation 'com.firebaseui:firebase-ui-storage:0.6.0'
implementation 'com.android.support:palette-v7:27.1.1'
//Compile SDK Version - Glide must be compiled against SDK version 27 (Oreo MR1) or higher.
//Support Library Version - Glide uses support library version 27.
//Compile SDK Version - Glide must be compiled against SDK version 27 (Oreo MR1) or higher.
//Support Library Version - Glide uses support library version 27.
annotationProcessor 'com.github.bumptech.glide:compiler:4.7.1'
implementation("com.github.bumptech.glide:glide:4.7.1")
{
exclude group: "com.android.support"
}
// implementation 'com.github.bumptech.glide:glide:4.7.1'
implementation 'com.lorentzos.swipecards:library:1.0.9'
implementation 'com.android.support.constraint:constraint-layout:1.1.0'
//////////////////////////////////////////////////////////////////////////////////////////////////
// If you use Glide’s annotations on classes implemented in Kotlin, you need to include a kapt
// dependency on Glide’s annotation processor instead of a annotationProcessor dependency
//////////////////////////////////////////////////////////////////////////////////////////////////
//for image crop
implementation "com.theartofdev.edmodo:android-image-cropper:2.4.7"
}
//apply plugin: 'kotlin-kapt'
apply plugin: 'com.google.gms.google-services'
Here is where I'm trying to get the Download URL of the image I just uploaded successfully in storage . It is storing the location of the file path in the database into my profileImageURL variable when I want it to be the downloadURL value.
Code is saving user data and images using SettingsActivity.java below.
The problem is it should be storing a link similar to:
https://firebasestorage.googleapis.com/v0/b/appname.appspot.com/o/profileImages%2FpqAIiU7589S64RiTi4rdDhjR6KQ2?alt=media&token=bef1884e-44a0-4229-ad26-89381cf2d03a
but instead it's loading the file location into downloadUrl variable and profileImageUrl in Firebase database.:
gs://appname.appspot.com/profileImages/pqAIiU2389434RiTi4rdDhjR6KQ2
It used to work with this command until I started changing code to fix other errors. Compiler was telling me getDownloadUrl() was unknown code.
//Uri downloadUrl = taskSnapshot.getDownloadUrl(); //Depreciated
What it appears like in my database. Everything is working more or less, but the image won't load on the device because it clearly isn't getting the right location right now. It does grab the image when a new user is created and "default" case statement displays the ic_launcher image. Also, my images are stored in a folder of the Firebase storage called profileImages/
//////////////////////////////////////////////////
package com.example.cell.der;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.ChildEventListener;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import com.google.firebase.storage.FirebaseStorage;
import com.google.firebase.storage.StorageReference;
import com.google.firebase.storage.UploadTask;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class SettingsActivity extends AppCompatActivity {
private EditText mNameField, mPhoneField;
private Button mBack, mConfirm;
private ImageView mProfileImage;
private FirebaseAuth mAuth;
private DatabaseReference mUserDatabase;
private String userId, name, phone, profileImageUrl, userSex;
private Uri resultUri;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
//Get Views (fields/buttons) from XML by using findViewById
mNameField = (EditText) findViewById(R.id.name);
mPhoneField = (EditText) findViewById(R.id.phone);
mProfileImage = (ImageView) findViewById(R.id.profileImage);
mBack = (Button) findViewById(R.id.back);
mConfirm = (Button) findViewById(R.id.confirm);
mAuth = FirebaseAuth.getInstance();
userId = mAuth.getCurrentUser().getUid();
mUserDatabase = FirebaseDatabase.getInstance().getReference().child("Users").child(userId);
getUserInfo();
//Attach onClickListeners to Views (fields/buttons)
mProfileImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
startActivityForResult(intent, 1);
}
});
mConfirm.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
saveUserInformation();
}
});
mBack.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
return;
}
});
}
....
....
//Save User's information into Firebase database
private void saveUserInformation() {
name = mNameField.getText().toString();
phone = mPhoneField.getText().toString();
Map userInfo = new HashMap();
userInfo.put("name", name);
userInfo.put("phone", phone);
//Update the current values stored in the Firebase Instance for current userId
mUserDatabase.updateChildren(userInfo);
if(resultUri != null){
StorageReference filepath = FirebaseStorage.getInstance().getReference().child("profileImages").child(userId);
Bitmap bitmap = null;
try {
bitmap = MediaStore.Images.Media.getBitmap(getApplication().getContentResolver(), resultUri);
} catch (IOException e) {
e.printStackTrace();
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 20, baos);
byte[] data = baos.toByteArray();
UploadTask uploadTask = filepath.putBytes(data);
uploadTask.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
finish();
}
});
uploadTask.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
@Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
//Uri downloadUrl = taskSnapshot.getDownloadUrl(); //Depreciated
//final StorageReference downloadUrl = FirebaseStorage.getInstance().getReference("profileImages/").getDownloadUrl();
StorageReference downloadUrl = FirebaseStorage.getInstance().getReference().child("profileImages").child(userId);
Map userInfo = new HashMap();
userInfo.put("profileImageUrl", downloadUrl.toString());
mUserDatabase.updateChildren(userInfo);
finish();
return;
}
});
}else{
finish();
}
My other question was related to best practice. I read getDownloadUrl() was not the best because the URL's are exposed and someone could cause problems (Firebase data consumption for example). How would I make this more secure if that is the case? Really looking for example code in relation Firebase and how I structured mine if possible. Using GLide 4.7.1, AS 3.1.2.