따라서 안전한 스토리지가 필요합니다. 오른쪽?

앱 사용자가 콘텐츠를 생성하고 안전하게 저장할 수 있다면 좋지 않을까요?



AWS Amplify가 도와드리겠습니다.



오늘은 AWS Amplify 스토리지를 사용하여 Android 앱에서 사진을 업로드하고 보는 방법을 보여드리겠습니다. 시리즈의 첫 번째 게시물에서 만든 MyAuthApplication 앱에 이 기능을 추가합니다.






  • 아래와 같이 build.gradle(Project: MyAuthApplication)을 업데이트합니다
  • .



    // Top-level build file where you can add configuration options common to all sub-projects/modules.
    buildscript {
        repositories {
            google()
            jcenter()
    
            maven { url '<https://jitpack.io>' }
        }
        dependencies {
            classpath "com.android.tools.build:gradle:4.0.1"
    
            // NOTE: Do not place your application dependencies here; they belong
            // in the individual module build.gradle files
        }
    }
    
    allprojects {
        repositories {
            google()
            jcenter()
    
    
            maven { url '<https://jitpack.io>' }
    
        }
    }
    
    task clean(type: Delete) {
        delete rootProject.buildDir
    }
    



  • 아래와 같이 build.gradle(모듈:앱)을 업데이트합니다
  • .



    apply plugin: 'com.android.application'
    
    android {
        compileSdkVersion 29
    
        defaultConfig {
            applicationId "com.offlineprogrammer.myauthapplication"
            minSdkVersion 23
            targetSdkVersion 29
            versionCode 1
            versionName "1.0"
    
            testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        }
    
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            }
        }
    
        compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_8
            targetCompatibility JavaVersion.VERSION_1_8
        }
    }
    
    dependencies {
        implementation fileTree(dir: "libs", include: ["*.jar"])
        implementation 'androidx.appcompat:appcompat:1.2.0'
        implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
        testImplementation 'junit:junit:4.12'
        androidTestImplementation 'androidx.test.ext:junit:1.1.2'
        androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
    
        implementation 'com.google.android.material:material:1.2.1'
        implementation 'androidx.recyclerview:recyclerview:1.1.0'
    
        implementation 'com.amplifyframework:core:1.1.2'
        implementation 'com.amplifyframework:aws-storage-s3:1.1.2'
        implementation 'com.amplifyframework:aws-auth-cognito:1.1.2'
    
        implementation 'com.github.esafirm.android-image-picker:imagepicker:2.3.0'
        implementation 'com.github.esafirm.android-image-picker:rximagepicker:2.3.0'
        implementation 'com.github.bumptech.glide:glide:4.11.0'
        annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
    
    }
    



  • Gradle 동기화를 실행해야 합니다
  • .
  • MyAuthApplication 클래스를 업데이트하여 아래와 같이 저장소 플러그인을 추가합니다
  • .



    public class MyAuthApplication  extends Application {
        private static final String TAG = "MyAuthApplication";
    
        @Override
        public void onCreate() {
            super.onCreate();
    
            try {
                Amplify.addPlugin(new AWSCognitoAuthPlugin());
                Amplify.addPlugin(new AWSS3StoragePlugin());
    
                Amplify.configure(getApplicationContext());
    
                Log.i(TAG, "Initialized Amplify");
            } catch (AmplifyException error) {
                Log.e(TAG, "Could not initialize Amplify", error);
            }
    
        }
    }
    



  • 아래 명령을 실행하여 스토리지 범주를 구성합니다
  • .



    amplify add storage
    



  • 메시지가 표시되면 아래 세부 정보를 설정합니다
  • .



    Please select from one of the below mentioned services: Content (Images, audio, video, etc.)
    ? Please provide a friendly name for your resource that will be used to label this category in the project: s34b23f393
    ? Please provide bucket name: myauthapplication00496853c7404e93a752634a073f09
    ? Who should have access: Auth users only
    ? What kind of access do you want for Authenticated users? create/update, read, delete
    ? Do you want to add a Lambda Trigger for your S3 Bucket? No
    Successfully added resource s34b23f393 locally
    
    If a user is part of a user pool group, run "amplify update storage" to enable IAM group policies for CRUD operations
    Some next steps:
    "amplify push" builds all of your local backend resources and provisions them in the cloud
    "amplify publish" builds all of your local backend and front-end resources (if you added hosting category) and provisions them in the cloud
    
    



  • 아래 명령을 실행하여 해당 변경 사항을 게시합니다
  • .



    amplify push
    



  • 완료되면 아래와 같이 확인 메시지가 표시됩니다
  • .



    ✔ All resources are updated in the cloud
    
    



  • 새 빈 활동을 추가합니다. 이름을 GalleryActivity
  • 로 지정합니다.



  • 아래와 같이 ImageUrl 클래스를 생성합니다.



  • public class ImageUrl {
        String imageUrl;
    
        public String getImageUrl() {
            return imageUrl;
        }
    
        public void setImageUrl(String imageUrl) {
            this.imageUrl = imageUrl;
        }
    }
    
    



  • ImageUrlsAdapter 클래스를 만듭니다
  • .



    public class ImageUrlsAdapter extends RecyclerView.Adapter<ImageUrlsAdapter.ViewHolder> {
        private static final String TAG = "ImageUrlsAdapter";
        private ArrayList<ImageUrl> imageUrls;
        private Context context;
    
        public ImageUrlsAdapter(Context context, ArrayList<ImageUrl> imageUrls) {
            this.context = context;
            this.imageUrls = imageUrls;
    
        }
    
        @Override
        public ImageUrlsAdapter.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
            View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.image_itemview, viewGroup, false);
            return new ViewHolder(view);
        }
    
        public void add(ImageUrl item, int position) {
            imageUrls.add(position, item);
            Log.i(TAG, "add: " + item.toString());
            notifyItemInserted(position);
            //notifyDataSetChanged();
            //notifyItemRangeChanged(0, getItemCount());
        }
    
        /**
         * gets the image url from adapter and passes to Glide API to load the image
         *
         * @param viewHolder
         * @param i
         */
        @Override
        public void onBindViewHolder(ViewHolder viewHolder, int i) {
            Glide.with(context).load(imageUrls.get(i).getImageUrl()).into(viewHolder.img);
        }
    
        @Override
        public int getItemCount() {
            return imageUrls.size();
        }
    
        public class ViewHolder extends RecyclerView.ViewHolder {
    
            ImageView img;
    
            public ViewHolder(View view) {
                super(view);
                img = view.findViewById(R.id.imageView);
            }
        }
    }
    



  • 새 레이아웃 파일 image_itemview.xml을 추가합니다. 아래와 같이 imageVew에 사용합니다
  • .



    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="180dp"
        android:layout_height="180dp"
        android:orientation="vertical">
    
        <ImageView
            android:id="@+id/imageView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="fitXY" />
    </LinearLayout>
    



  • 아래와 같이 activity_gallery.xml을 업데이트하여 Button 및 RecyclerView를 추가합니다
  • .



    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".GalleryActivity">
    
        <androidx.appcompat.widget.AppCompatButton
            android:id="@+id/camera_button"
            android:layout_width="wrap_content"
            android:layout_height="50dp"
            android:layout_marginTop="10dp"
            android:text="Select Photo"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_alignParentBottom="true"
            android:scrollbars="vertical"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.0"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@id/camera_button"
            app:layout_constraintVertical_bias="0.0" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    



  • 사용자가 성공적으로 로그인하면 GalleryActivity를 열도록 MainActivity를 업데이트합니다
  • .



    public class MainActivity extends AppCompatActivity {
        private static final String TAG = "MainActivity";
        ImageButton login_with_amazon;
        TextView login_textView;
        ProgressBar log_in_progress;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            login_with_amazon = findViewById(R.id.login_with_amazon);
            login_textView = findViewById(R.id.login_textView);
            log_in_progress = findViewById(R.id.log_in_progress);
    
            login_with_amazon.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    log_in_progress.setVisibility(View.VISIBLE);
                    login_with_amazon.setVisibility(View.GONE);
                    login();
                }
            });
    
        }
    
        private void login() {
            Amplify.Auth.signInWithSocialWebUI(
                    AuthProvider.amazon(),
                    this,
                    result -&gt; {
                        Log.i(TAG, " RESULT " + result.toString());
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                login_textView.setText("Login is successfull");
                                login_with_amazon.setVisibility(View.GONE);
                                log_in_progress.setVisibility(View.GONE);
                                startActivity(new Intent(MainActivity.this, GalleryActivity.class));
                                finish();
                            }
                        });
                    },
                    error -&gt; {
                        Log.e(TAG, " ERROR " + error.toString());
                    }
            );
    
        }
    
        @Override
        protected void onNewIntent(Intent intent) {
            super.onNewIntent(intent);
    
            if(intent.getData() != null &amp;&amp; "myauthapp".equals(intent.getData().getScheme())) {
                Amplify.Auth.handleWebUISignInResponse(intent);
            }
        }
    
    }
    



  • GalleryActivity에서 이미지를 업로드하는 기능과 저장소의 이미지를 나열하는 또 다른 기능을 만듭니다. GalleryActivity
  • 는 아래를 참조하십시오.



    public class GalleryActivity extends AppCompatActivity {
        private static final String TAG = "GalleryActivity";
        RecyclerView recyclerView;
        GridLayoutManager gridLayoutManager;
        AWSCognitoAuthSession cognitoAuthSession;
        ImageUrlsAdapter dataAdapter;
        private Button camera_button;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_gallery);
            recyclerView = findViewById(R.id.recyclerView);
            camera_button = findViewById(R.id.camera_button);
            gridLayoutManager = new GridLayoutManager(getApplicationContext(), 2);
            recyclerView.setLayoutManager(gridLayoutManager);
    
            camera_button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    ImagePicker.create(GalleryActivity.this).returnMode(ReturnMode.ALL)
                            .folderMode(true).includeVideo(false).limit(1).theme(R.style.AppTheme_NoActionBar).single().start();
                }
            });
    
            Amplify.Auth.fetchAuthSession(
                    result -&gt; {
                        cognitoAuthSession = (AWSCognitoAuthSession) result;
                        switch (cognitoAuthSession.getIdentityId().getType()) {
                            case SUCCESS:
                                ArrayList imageUrlList = new ArrayList&lt;&gt;();
                                dataAdapter = new ImageUrlsAdapter(getApplicationContext(), imageUrlList);
                                runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        recyclerView.setAdapter(dataAdapter);
                                    }
                                });
                                prepareData();
                                break;
                            case FAILURE:
                                Log.i(TAG, "IdentityId not present because: " + cognitoAuthSession.getIdentityId().getError().toString());
                        }
                    },
                    error -&gt; Log.e(TAG, error.toString())
            );
        }
    
        public void onActivityResult(int i, int i2, Intent intent) {
            super.onActivityResult(i, i2, intent);
            if (ImagePicker.shouldHandle(i, i2, intent)) {
                Image firstImageOrNull = ImagePicker.getFirstImageOrNull(intent);
                if (firstImageOrNull != null) {
                    uploadImage(firstImageOrNull.getPath());
                }
            }
        }
    
        private void uploadImage(String path) {
            if (path != null) {
                StorageUploadFileOptions options =
                        StorageUploadFileOptions.builder()
                                .accessLevel(StorageAccessLevel.PROTECTED)
                                .targetIdentityId(cognitoAuthSession.getIdentityId().getValue())
                                .build();
                File exampleFile = new File(path);
                Amplify.Storage.uploadFile(
                        UUID.randomUUID().toString(),
                        exampleFile,
                        result -&gt; {
                            Log.i(TAG, "Successfully uploaded: " + result.getKey());
                            Amplify.Storage.getUrl(result.getKey(),
                                    getUrlResult -&gt; {
    
                                        Log.i(TAG, "Url: " + getUrlResult.getUrl());
    
                                        ImageUrl imageUrl = new ImageUrl();
                                        imageUrl.setImageUrl(getUrlResult.getUrl().toString());
                                        runOnUiThread(new Runnable() {
                                            @Override
                                            public void run() {
                                                dataAdapter.add(imageUrl, 0);
                                            }
                                        });
                                    },
                                    getUrlError -&gt; Log.e(TAG, "prepareData: ", getUrlError));
                        },
                        storageFailure -&gt; Log.e(TAG, "Upload failed", storageFailure)
                );
            }
        }
    
        private void prepareData() {
            Amplify.Storage.list(
                    "",
                    result -&gt; {
                        for (StorageItem item : result.getItems()) {
                            Log.i(TAG, "Item: " + item.getKey());
                            Amplify.Storage.getUrl(item.getKey(),
                                    getUrlResult -&gt; {
                                        Log.i(TAG, "Url: " + getUrlResult.getUrl());
                                        ImageUrl imageUrl = new ImageUrl();
                                        imageUrl.setImageUrl(getUrlResult.getUrl().toString());
                                        runOnUiThread(new Runnable() {
                                            @Override
                                            public void run() {
                                                dataAdapter.add(imageUrl, 0);
                                            }
                                        });
                                    },
                                    getUrlError -&gt; Log.e(TAG, "prepareData: ", getUrlError));
                        }
                    },
                    error -&gt; Log.e(TAG, "List failure", error)
            );
        }
    }
    



  • 앱을 실행합니다. 로그인에 성공하면 아래와 같이 사진을 업로드할 수 있습니다
  • .






    github에서 전체 코드를 확인하십시오.

    #coding, #learning, #technology, #Java, #JavaScript, #Autism, #Parenting...등에 대한 더 많은 팁을 보려면 저를 팔로우하세요.

    내 앱 확인Google Play

    좋은 웹페이지 즐겨찾기