首页 > 解决方案 > StorageReference downloadUrl 获取 URL 失败

问题描述

希望我对我在获取图像下载 URL 时犯的错误有一个简单的答案。这是可行的,但在修复了许多其他编译问题后停止了,其中一些与 Gradle 实现版本有关。显然表明我无法理解 Firebase StorageReference 编码文档。我发现大多数程序员都不知道如何为傻瓜编写文档:)。

从我阅读的一些信息中,我也有一个与最佳实践相关的安全问题。感谢您提供的任何答案。

所以这是我的 App Gradle 文件:

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

这是我试图获取刚刚在 storage 中成功上传的图像的下载 URL 的地方。当我希望它是 downloadURL 值时,它将数据库中文件路径的位置存储到我的 profileImageURL 变量中。

代码使用下面的 SettingsActivity.java 保存用户数据和图像。
问题是它应该存储类似于以下内容的链接:

https://firebasestorage.googleapis.com/v0/b/appname.appspot.com/o/profileImages%2FpqAIiU7589S64RiTi4rdDhjR6KQ2?alt=media&token=bef1884e-44a0-4229-ad26-89381cf2d03a

而是将文件位置加载到 Firebase 数据库中的 downloadUrl 变量和 profileImageUrl 中。:

gs://appname.appspot.com/profileImages/pqAIiU2389434RiTi4rdDhjR6KQ2 

在我开始更改代码以修复其他错误之前,它曾经使用此命令。编译器告诉我 getDownloadUrl() 是未知代码。

//Uri downloadUrl = taskSnapshot.getDownloadUrl();  //Depreciated

它在我的数据库中的样子。一切都或多或少地工作,但图像不会加载到设备上,因为它现在显然没有得到正确的位置。当创建新用户并且“默认”case 语句显示 ic_launcher 图像时,它会抓取图像。此外,我的图像存储在 Firebase 存储的一个名为 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();
        }     

我的另一个问题与最佳实践有关。我读到 getDownloadUrl() 不是最好的,因为 URL 是暴露的,有人可能会导致问题(例如 Firebase 数据消耗)。如果是这样,我将如何使这更安全? 如果可能的话,真的在寻找与 Firebase 相关的示例代码以及我如何构建我的代码。 使用 GLide 4.7.1、AS 3.1.2。

标签: androidfirebasefirebase-storage

解决方案


推荐阅读