0

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/ enter image description here

//////////////////////////////////////////////////
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.

Joe
  • 35
  • 8
  • @Doug Stevenson `Non-static method 'getDownloadUrl()' cannot be referenced from a static contex` is the message I get when using the following line. `Uri downloadUrl = StorageReference.getDownloadUrl();` That still gives an underlined in red function call. I know lots of people have asked this question, but the answers don't make sense/show me how I'm supposed to get the Firebase image downloadURL. – Joe Jun 05 '18 at 02:41
  • You need a StorageReference object to call that method on, not the StorageReference class object itself. – Doug Stevenson Jun 05 '18 at 02:47
  • Do you have an example Doug? Based on your reputation you're a guru at this, and based on mine, I'm not. I don't teach people how to drive by explaining engine combustion lol :) I'm looking for some assistance such as: `Open door() { put on seat belt; press break; turn key; finish(); }` Appreciate your suggestions. My code also shows I was working with FirebaseReference getDownloadUrl() too. I just can't figure out how to pull the value from Firebase. – Joe Jun 05 '18 at 02:53
  • There is documentation for this. https://firebase.google.com/docs/storage/android/download-files#download_data_via_url – Doug Stevenson Jun 05 '18 at 02:56
  • Thanks. It wasn't helpful to me unfortunately. – Joe Jun 06 '18 at 00:27

0 Answers0