使用 Amazon Amplify快速创建简单的 Android 应用程序

Posted 大前端之旅

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用 Amazon Amplify快速创建简单的 Android 应用程序相关的知识,希望对你有一定的参考价值。

背景:

大家好,我是坚果,由于最近一直疫情居家,所以想到外边转转,但是确实出不去,那么作为程序员的我们肯定也不能闲着,于是想做一个很简单的旅行应用,具有基础的增删改查的功能。以及身份验证!这个时候考虑到Amazon 具有高响应,高可用等特点,这个时候你只要Amazon 结合一定的android基础,就可以很方便快捷的拥有自己的应用程序。而且由于Amazon 具有全球优势的特点,以及Amazon Amplify 是一组位于云端的工具和无服务器服务都让他拥有了一定的优势,这样一来技术选型接确定了,那么说了这么多,如何结合Amazon 很快的创建属于自己的Android 应用程序呢?只需要简单的五个步骤就可以。接下来开始正文

开始之前看一下具体你要具备哪些条件:

先决条件

检查noidejs版本,node -v,发现版本是16.13.0,符合条件

android studio 版本查看方式

点击help-about,如图所示:版本符合要求

接下来构建您的首个 Android 应用程序

概览

在本文中,您将使用 Amazon Amplify 创建一个简单的 Android 应用程序,Amazon Amplify 是一组位于云端的工具和无服务器服务。在第一个单元中,您将构建一个简单的 Android 应用程序。在其余单元中,您将使用 Amplify 命令行接口 (Amplify CLI) 初始化一个本地应用程序、添加用户身份验证、添加一个 GraphQL API 和一个数据库以存储您的数据,并更新您的应用程序以存储图像。

本文将引导您完成创建上面讨论的简单 Android 应用程序。

本文分为五个简短单元。您必须按顺序完成每个单元才能进入下一单元。

使用 Amazon Amplify 创建简单的 Android 应用qq

​ 1.构建 Android 应用程序

​ 在 Android 模拟器中创建 Android 应用程序并测试

​ 2.初始化本地应用程序

​ 使用 Amazon Amplify 初始化本地应用程序

​ 3.添加身份验证

​ 添加身份验证到您的应用程序中

​ 4.添加API和数据库

​ 创建 GraphQL API

​ 5.添加存储

​ 添加存储到您的应用程序中

您将使用终端和 Google 的 Android Studio IDE 来构建此 Android 应用程序。

1.创建和部署 Android 应用程序

在这,您将创建 Android 应用程序并使用 Amazon Amplify 的 Web 托管服务将其部署到云中。

1.1简介

Amazon Amplify 提供基于 Git 的工作流,用于创建、管理、集成和部署 Web 和移动应用程序的无服务器后端。Amplify CLI 提供了一个简单的基于文本的用户界面,用于预置和管理后端服务,如用于您的应用程序的用户身份验证或 REST 或 GraphQL API。使用 Amplify 库可以轻松地将这些后端服务与应用程序中的几行代码集成。

1.2实施

1.2.1.创建 Android 项目

启动 Android Studio,然后选择New Project

Phone and Tablet 下,选择 Basic Activity,然后单击 Next

为您的项目键入名称,例如 Android Amazon Started。确保语言为 Kotlin,开发工具包最低为 API 26: Android 8.0 (oreo),然后单击 Finish

现在,项目的框架已经存在,我们需要完成 4 个步骤来让我们的基本应用程序运行:

  1. 删除不需要的类和文件,并添加插件
  2. 创建类以保留数据结构
  3. 创建视图以在列表中保留单个备注
  4. 修改 MainActivity 以显示备注列表

1.2.2.删除不需要的类和文件,并添加插件

在“res/layout”和 java/com.example.androidgettingstarted 下,删除四个片段文件(选择这 4 个文件,右键单击,然后从上下文菜单中选择 Delete ):

Gradle Scripts下,打开 build.gradle (Module:app),并添加 Kotlin 扩展插件。

plugins 


    id 'com.android.application'


    id 'kotlin-android'


    id 'kotlin-android-extensions' //  <== add this line



1.2.3.创建类以保留数据结构

UserData 类可保留用户状态:一个 isSignedIn 标记和一个备注值列表。

要创建新类,请右键单击 java/com.example/androidgettingstarted,然后选择 New -> Kotlin file/class。键入 UserData 作为名称。

将以下代码粘贴到新创建的文件 (UserData.kt) 中

package com.example.androidgettingstarted





import android.graphics.Bitmap


import android.util.Log


import androidx.lifecycle.LiveData


import androidx.lifecycle.MutableLiveData





// a singleton to hold user data (this is a ViewModel pattern, without inheriting from ViewModel)


object UserData 





    private const val TAG = "UserData"





    //


    // observable properties


    //





    // signed in status


    private val _isSignedIn = MutableLiveData<Boolean>(false)


    var isSignedIn: LiveData<Boolean> = _isSignedIn





    fun setSignedIn(newValue : Boolean) 


        // use postvalue() to make the assignation on the main (UI) thread


        _isSignedIn.postValue(newValue)


    





    // the notes


    private val _notes = MutableLiveData<MutableList<Note>>(mutableListOf())





    // please check https://stackoverflow.com/questions/47941537/notify-observer-when-item-is-added-to-list-of-livedata


    private fun <T> MutableLiveData<T>.notifyObserver() 


        this.postValue(this.value)


    


    fun notifyObserver() 


        this._notes.notifyObserver()


    





    fun notes() : LiveData<MutableList<Note>>  = _notes


    fun addNote(n : Note) 


        val notes = _notes.value


        if (notes != null) 


            notes.add(n)


            _notes.notifyObserver()


         else 


            Log.e(TAG, "addNote : note collection is null !!")


        


    


    fun deleteNote(at: Int) : Note?  


        val note = _notes.value?.removeAt(at)


        _notes.notifyObserver()


        return note


    


    fun resetNotes() 


        this._notes.value?.clear()  //used when signing out


        _notes.notifyObserver()


    


    data class Note(val id: String, val name: String, val description: String, var imageName: String? = null) 


        override fun toString(): String = name


        // bitmap image


        var image : Bitmap? = null

    



我们刚刚添加了哪些内容?

  • UserData 类负责保留用户数据,即一个 isSignedIn 标记用于跟踪当前的身份验证状态和备注对象列表。

  • 这两个属性是根据 LiveData 发布/订阅框架来实现的。它允许图形用户界面 (GUI) 订阅更改并做出相应反应。

  • 我们还添加了一个备注数据类,仅用于保留单个备注的数据。针对 ImageName 和 Image 使用了两个不同的属性。我们将在后续单元中介绍 Image。

  • 为 UserData 对象实施了单态设计模式,因为此模式允许只使用 UserData 即可从应用程序的任何位置引用此对象。

1.2.4.为列表中的但各单元格添加GUI

滚动列表中的单个单元格称为 RecyclerView,因为当用户上下滚动屏幕,屏幕上再也看不到视图时,可以回收视图。

与常规视图一样,我们也创建了布局 XML 文件和 Kotlin 类。单个单元格类似以下内容:

要创建布局文件,请右键单击“res/layout”,然后选择 New -> Layout Resource File。键入 content_note 作为名称,并保留所有其他值,因为我们将直接编辑 XML 文件。

打开新创建的文件的 Code 视图。

在新创建的文件 (content_note.xml) 的“Code”视图中,通过粘贴以下代码来替代所生成的代码:

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"


    android:layout_width="match_parent"


    android:layout_height="wrap_content"


    android:orientation="horizontal"


    android:paddingVertical="16dp">





    <ImageView


        android:id="@+id/image"


        android:layout_width="100dp"


        android:layout_height="match_parent"


        android:padding="8dp"


        android:scaleType="centerCrop"


        android:src="@drawable/ic_launcher_background" />





    <LinearLayout


        android:layout_width="match_parent"


        android:layout_height="wrap_content"


        android:layout_gravity="center"


        android:layout_marginLeft="5dp"


        android:orientation="vertical">





        <TextView


            android:id="@+id/name"


            android:layout_width="match_parent"


            android:layout_height="wrap_content"


            android:text="Title"


            android:textSize="20sp"


            android:textStyle="bold" />





        <TextView


            android:id="@+id/description"


            android:layout_width="match_parent"


            android:layout_height="wrap_content"


            android:text="Title"


            android:textSize="15sp" />





    </LinearLayout>


</LinearLayout>

最后,创建 Kotlin 类:右键单击 java/com.example/androidgettingstarted,然后选择 New -> Kotlin file/class。键入 NoteRecyclerViewAdapter 作为名称。

将以下代码粘贴到新创建的文件 (NoteRecyclerViewAdapter.kt) 中

package com.example.androidgettingstarted





import android.view.LayoutInflater


import android.view.View


import android.view.ViewGroup


import android.widget.ImageView


import android.widget.TextView


import androidx.recyclerview.widget.RecyclerView





// this is a single cell (row) in the list of Notes


class NoteRecyclerViewAdapter(


    private val values: MutableList<UserData.Note>?) :


    RecyclerView.Adapter<NoteRecyclerViewAdapter.ViewHolder>() 





    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder 


        val view = LayoutInflater.from(parent.context)


            .inflate(R.layout.content_note, parent, false)


        return ViewHolder(view)


    





    override fun onBindViewHolder(holder: ViewHolder, position: Int) 





        val item = values?.get(position)


        holder.nameView.text = item?.name


        holder.descriptionView.text = item?.description





        if (item?.image != null) 


            holder.imageView.setImageBitmap(item.image)


        


    





    override fun getItemCount() = values?.size ?: 0





    inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) 


        val imageView: ImageView = view.findViewById(R.id.image)


        val nameView: TextView = view.findViewById(R.id.name)


        val descriptionView: TextView = view.findViewById(R.id.description)


    



我们刚刚添加了哪些内容?

上述代码包含

  • 一个布局 xml 文件,该文件说明表示备注的单元格上的组件布局。它显示图像、备注标题和备注说明。

  • 一个支持 Kotlin 类。它在创建时接收备注数据对象,并将单个值分配给其相对应的视图(图像、标题和说明)

1.2.5.更新主要活动

现在,我们已经有了数据类(UserData 和备注)和单个备注的视图 (NoteRecyclerViewAdapter),让我们在主要活动上创建备注列表。

从 Android Studio 左侧的文件列表,打开 res/layout/content_main.xml,并将代码替换为以下内容:

<?xml version="1.0" encoding="utf-8"?>


<FrameLayout 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:id="@+id/frameLayout"


    android:layout_width="match_parent"


    android:layout_height="match_parent"


    >





    <androidx.recyclerview.widget.RecyclerView


        android:id="@+id/item_list"


        android:name="com.example.myapplication.ItemListFragment"


        android:layout_width="match_parent"


        android:layout_height="match_parent"


        android:layout_marginTop="60dp"





        android:paddingHorizontal="8dp"


        android:paddingVertical="8dp"


        app:layoutManager="LinearLayoutManager"


        tools:context=".MainActivity"


        tools:listitem="@layout/content_note" />





</FrameLayout>

从 Android Studio 左侧的文件列表,打开 java/com.example/androidgettingstarted/MainActivity.kt,并将代码替换为以下内容:

package com.example.androidgettingstarted





import android.os.Bundle


import android.util.Log


import androidx.appcompat.app.AppCompatActivity


import androidx.lifecycle.Observer


import androidx.recyclerview.widget.ItemTouchHelper


import androidx.recyclerview.widget.RecyclerView


import kotlinx.android.synthetic.main.activity_main.*


import kotlinx.android.synthetic.main.content_main.*





class MainActivity : AppCompatActivity() 





    override fun onCreate(savedInstanceState: Bundle?) 


        super.onCreate(savedInstanceState)


        setContentView(R.layout.activity_main)


        setSupportActionBar(toolbar)





        // prepare our List view and RecyclerView (cells)


        setupRecyclerView(item_list)


    





    // recycler view is the list of cells


    private fun setupRecyclerView(recyclerView: RecyclerView) 





        // update individual cell when the Note data are modified


        UserData.notes().observe(this, Observer<MutableList<UserData.Note>>  notes ->


            Log.d(TAG, "Note observer received $notes.size notes")





            // let's create a RecyclerViewAdapter that manages the individual cells


            recyclerView.adapter = NoteRecyclerViewAdapter(notes)


        )


    





    companion object 


        private const val TAG = "MainActivity"


    



我们刚刚添加了哪些内容?

  • 主要布局是一个 RecyclerView,用于管理我们之前创建的单个单元格列表

  • 主要活动类可观察备注列表的变化,并创建一个 NoteRecyclerViewAdapter 以创建单个单元格。

1.2.6.验证生成依赖项

  • Gradle Scripts下,打开 build.gradle (Module:app),并验证所生成的依赖关系是否正确。需要选中

**libraries versions**

```gradle


dependencies 


    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"


    implementation 'androidx.core:core-ktx:1.3.2'


    implementation 'androidx.appcompat:appcompat:1.2.0'


    implementation 'com.google.android.material:material:1.2.1'


    implementation 'androidx.constraintlayout:constraintlayout:2.0.2'


    implementation 'androidx.navigation:navigation-fragment-ktx:2.3.1'


    implementation 'androidx.navigation:navigation-ui-ktx:2.3.1'


    testImplementation 'junit:junit:4.+'


    androidTestImplementation 'androidx.test.ext:junit:1.1.2'


    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'



1.2.7.构建和测试

  • 现在,请在模拟器中构建并启动应用程序。单击工具栏中的运行图标 ▶️ 或按 ^ R

片刻之后,应用程序会在 Android 模拟器中启动,初始屏幕为空。

在此阶段,没有要在运行时呈现的数据。到此您已成功创建 Android 应用程序。接下来开始使用 Amplify 进行构建!

2.初始化 Amplify

在此单元中,您将安装并配置 Amplify CLI。

2.1简介

现在我们已创建一个 Android 应用程序,我们想要继续开发并添加新功能。

要开始在应用程序中使用 Amazon Amplify,必须安装 Amplify 命令行,初始化 Amplify 项目目录,将项目配置为使用 Amplify 库,并在运行时初始化 Amplify 库。

2.2实施

2.2.1安装Amplify CLI

Amazon Amplify CLI 取决于 Node.js,没有安装的化,请安装。

要安装 Amazon Amplify CLI,请打开一个终端,然后输入以下命令

## Install Amplify CLI


npm install -g @aws-amplify/cli

查看版本:

## Verify installation and version


amplify --version





 7.6.26

2.2.2初始化Amplify后端

要创建后端基本结构,首先需要初始化 Amplify 项目目录并创建云后端。

打开项目所在目录,输入cmd,即可打开终端

验证您是否在正确的目录中,它应该如下所示:

F:\\workspace\\AndroidASW>tree


卷 开发环境 的文件夹 PATH 列表


卷序列号为 D4D7-D5B3


F:.


├─.gradle


│  ├─7.0.2


│  │  ├─dependencies-accessors


│  │  ├─fileChanges


│  │  ├─fileHashes


│  │  └─vcsMetadata-1


│  ├─buildOutputCleanup


│  ├─checksums


│  └─vcs-1


├─.idea


│  ├─libraries


│  └─modules


│      └─app


├─app


│  ├─libs


│  └─src


│      ├─androidTest


│      │  └─java


│      │      └─com


│      │          └─example


│      │              └─androidasw


│      ├─main


│      │  ├─java


│      │  │  └─com


│      │  │      └─example


│      │  │          └─androidasw


│      │  └─res


│      │      ├─drawable


│      │      ├─drawable-v24


│      │      ├─layout


│      │      ├─menu


│      │      ├─mipmap-anydpi-v26


│      │      ├─mipmap-hdpi


│      │      ├─mipmap-mdpi


│      │      ├─mipmap-xhdpi


│      │      ├─mipmap-xxhdpi


│      │      ├─mipmap-xxxhdpi


│      │      ├─navigation


│      │      ├─values


│      │      ├─values-land


│      │      ├─values-night


│      │      ├─values-w1240dp


│      │      └─values-w600dp


│      └─test


│          └─java


│              └─com


│                  └─example


│                      └─androidasw


└─gradle


    └─wrapper





F:\\workspace\\AndroidASW>

接下来,在亚马逊服务管理后台创建对应的用户,并添加权限类型,具体如下图所示:

2.2.3控制台相关操作

第一步注册

[https://aws.amazon.com/cn/free/?trk=95502bdb-28e0-4dc1-895c-2e975a171d36&sc_channel=ba&all-free-tier.sort-by=item.additionalFields.SortRank&all-free-tier.sort-order=asc&awsf.Free%20Tier%20Types=](https://aws.amazon.com/cn/free/?trk=95502bdb-28e0-4dc1-895c-2e975a171d36&sc_channel=ba&all-free-tier.sort-by=item.additionalFields.SortRank&all-free-tier.sort-order=asc&awsf.Free Tier Types=)*all&awsf.Free%20Tier%20Categories=*all

登录控制台

添加权限

点击“下一步”,选择“直接附加现有策略”,一直“下一步",后会提示创建用户成功。

添加用户

到此,我们也就创建完成。接下来继续下面的步骤。

初始化 Amplify 项目结构和配置文件。运行以下命令

amplify init

? Enter a name for your project (androidgettingstarted): accept the default, press enter


? Enter a name for the environment (dev): accept the default, press enter


? Choose your default editor: use the arrow key to select your favorite text editor an press enter


? Choose the type of app that you're building: android is already selected, press enter


? Where is your Res directory: accept the default, press enter


? Do you want to use an AWS profile?, Y, press enter


? Please choose the profile you want to use: use the arrow keys to select your profile and press enter.

如果没有配置文件,可使用 Amazon CLI 键入命令 aws configure --profile 创建一个。

Amplify 在云中初始化您的项目,可能需要几分钟。几分钟后,您应该会看到如下消息:

2.2.4将Amplify库添加到项目中

Amplify for Android 是作为 Apache Maven 软件包分发的。在本部分中,您会将软件包和其他必需的指令添加到构建配置中。

返回 Android Studio,展开 Gradle Scripts 并打开 build.gradle (Project: Android_Getting_Started)。在 buildscript 和 allprojects 数据块的 repositories 数据块内添加行 mavenCentral()。

buildscript 


    ext.kotlin_version = "1.4.10"


    repositories 


        google()


        jcenter()





        // Add this line into `repositories` in `buildscript`


        mavenCentral()


    


    dependencies 


        classpath "com.android.tools.build:gradle:4.0.1"


        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"





        // NOTE: Do not place your application dependencies here; they belong


        // in the individual module build.gradle files


    








allprojects 


    repositories 


        google()


        jcenter()





        // Add this line into `repositories` in `buildscript`


        mavenCentral()


    



Gradle Scripts 下,打开 build.gradle (Module:app),并在 implementations 数据块中添加 Amplify 框架核心依赖项。

dependencies 


    implementation fileTree(dir: "libs", include: ["*.jar"])


    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"


    implementation 'androidx.core:core-ktx:1.3.2'


    implementation 'androidx.appcompat:appcompat:1.2.0'


    implementation 'com.google.android.material:material:1.2.1'


    implementation 'androidx.constraintlayout:constraintlayout:2.0.1'


    implementation 'androidx.navigation:navigation-fragment-ktx:2.3.0'


    implementation 'androidx.navigation:navigation-ui-ktx:2.3.0'


    testImplementation 'junit:junit:4.13'


    androidTestImplementation 'androidx.test.ext:junit:1.1.2'


    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'





    // Amplify core dependency


    implementation 'com.amplifyframework:core:1.4.0'



如果您使用 Java 或目标 Android SDK 21 或更早版本进行开发,请查看文档了解其他配置更改。

现在,运行 Gradle Sync

过一会儿您将看到

BUILD SUCCESSFUL in 1s

2.2.5在运行时初始化Amplify

我们来创建一个后端类对代码进行分组,以便与后端交互。我使用单例设计模式,使其通过应用程序轻松可用,并确保 Amplify 库仅初始化一次。

类初始化程序负责初始化 Amplify 库。

在 java/com.example.androidgettingstarted 下创建一个新的 Kotlin 文件 Backend.kt,打开它并添加以下代码:

package com.example.androidgettingstarted





import android.content.Context


import android.util.Log


import com.amplifyframework.AmplifyException


import com.amplifyframework.core.Amplify





object Backend 





    private const val TAG = "Backend"





    fun initialize(applicationContext: Context) : Backend 


        try 


            Amplify.configure(applicationContext)


            Log.i(TAG, "Initialized Amplify")


         catch (e: AmplifyException) 


            Log.e(TAG, "Could not initialize Amplify", e)


        


        return this


    



应用程序启动时,初始化单例 Backend 对象。

在 java/com.example.androidgettingstarted 下创建一个新的 Kotlin 文件 Application.kt,打开它并添加以下代码:

package com.example.androidgettingstarted





import android.app.Application





class AndroidGettingStartedApplication : Application() 





    override fun onCreate() 


        super.onCreate()





        // initialize Amplify when application is starting


        Backend.initialize(applicationContext)


    



在“manifests”下,打开 AndroidManifest.xml,并将应用程序类的名称添加到 元素。

    <!-- add the android:name attribute to the application node  -->


    <application


        android:name="AndroidGettingStartedApplication"


        android:allowBackup="true"


        android:icon="@mipmap/ic_launcher"


        android:label="@string/app_name"


        android:roundIcon="@mipmap/ic_launcher_round"


        android:supportsRtl="true"


        android:theme="@style/Theme.GettingStartedAndroid">


...

打开此文件后,请添加一些在本教程的后续步骤中应用程序需要的权限:

    <!-- add these nodes between manifest and application  -->


    <uses-permission android:name="android.permission.INTERNET"/>


    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>


    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

2.2.6验证您的设置

要验证一切是否都按预期运行,请构建并运行项目。单击工具栏中的运行图标 ▶️,或按 ^ R

要验证一切是否都按预期运行,请构建并运行项目。单击工具栏中的 运行 图标 ▶️ 或按 ^ R。

应该不会出现错误。

BUILD SUCCESSFUL in 6s

23 actionable tasks: 8 executed, 15 up-to-date

3.添加身份验证

在此单元中,您将使用 Amplify CLI 和库配置和添加身份验证到您的应用程序中。

3.1简介

您将添加的下一个功能是用户身份验证。在此单元中,您将了解如何使用 Amplify CLI 和库对用户进行身份验证,以利用托管用户身份提供商 Amazon Cognito

您还将了解如何使用 Cognito 托管用户界面展示整个用户身份验证流,从而使用户只需几行代码即可注册、登录和重置密码。

使用“托管用户界面”意味着应用程序利用 Cognito 网页登录和注册用户界面流。应用程序的用户将重定向到 Cognito 托管的网页,并在登录后重定向回应用程序。当然,Cognito 和 Amplify 也支持本机 UI。

3.2实施

3.2.1创建身份验证服务

要创建身份验证服务,请打开一个终端,然后执行以下命令:

amplify add auth

当您看到此消息时,即表示配置成功(资源的确切名称将有所不同):

Successfully added resource androidgettingstartedfc5a4717 locally

3.2.2部署身份验证服务

现在,已在本地配置身份验证服务,我们可以将它部署到云:在终端中,请在项目目录中执行以下命令

amplify push

# press Y when asked to continue

片刻之后,您应看到以下消息:

✔ All resources are updated in the cloud





Hosted UI Endpoint: https://androidgettingstarted-dev.auth.eu-central-1.amazoncognito.com/


Test Your Hosted UI Endpoint: https://androidgettingstarted-dev.auth.eu-central-1.amazoncognito.com/login?respons

3.2.3向项目添加Amplify身份验证库

在转到代码之前,请先返回 Android Studio,将以下依赖项连同您之前添加的其他

amplifyframework 实现一起,添加到您的单元的

build.gradle,然后在看到提示时,单击 Sync Now

dependencies 


    ...


    // Amplify core dependency


    implementation 'com.amplifyframework:core:1.4.0'


    implementation 'com.amplifyframework:aws-auth-cognito:1.4.0'



3.2.4在运行时配置Amplify身份验证库

返回 Android Studio,打开 Backend.kt 文件。在后端类中,向我们在上一部分(在 initialize() 方法中)添加的 Amplify 初始化代码添加一行

完整代码块应如下所示:

// inside Backend class


fun initialize(applicationContext: Context) : Backend 


    try 


        Amplify.addPlugin(AWSCognitoAuthPlugin())


        Amplify.configure(applicationContext)





        Log.i(TAG, "Initialized Amplify")


     catch (e: AmplifyException) 


        Log.e(TAG, "Could not initialize Amplify", e)


    


    return this



请不要忘记添加导入语句,Android Studio 会自动为您完成此操作(在 Mac 上,在代码编辑器检测到的每个错误上,同时按 Alt 和 Enter 键)。

像在上一步骤中那样,为每个缺少的类定义添加所需的导入语句(在红色单词上同时按 Alt 和 Enter 键)。

要验证一切是否都按预期运行,请构建项目。单击 Build 菜单,并选择 Make Project,或者,在 Mac 上按 ⌘F9。应该不会出现错误。

3.2.5在运行时触发身份验证

其余代码更改会跟踪用户的状态(他们是否已登录?)并在用户单击锁定图标时触发“SignIn/SignUp”用户界面。

a.添加 signIn 和 signOut 方法

在后端类中的任意位置,添加以下四种方法:

private fun updateUserData(withSignedInStatus : Boolean) 


    UserData.setSignedIn(withSignedInStatus)








fun signOut() 


    Log.i(TAG, "Initiate Signout Sequence")





    Amplify.Auth.signOut(


         Log.i(TAG, "Signed out!") ,


         error -> Log.e(TAG, error.toString()) 


    )








fun signIn(callingActivity: Activity) 


    Log.i(TAG, "Initiate Signin Sequence")





    Amplify.Auth.signInWithWebUI(


        callingActivity,


         result: AuthSignInResult ->  Log.i(TAG, result.toString()) ,


         error: AuthException -> Log.e(TAG, error.toString()) 


    )



然后为每个缺少的类定义添加所需的导入语句(在红色单词上按 Alt 和 Enter 键)。当您可以在多个类之间进行选择时,请务必从 Amplify 包中选择一个,如下面的屏幕截图所示。

请注意,我们没有在这些方法中更新 UserData.isSignedIn 标记,该操作将在下一节中完成。

b.添加身份验证中心侦听器

为了跟踪身份验证状态的变化,我们添加了代码以订阅由 Amplify 发送的身份验证事件。我们在 Backend.initialize() 方法中初始化该中心。

在收到身份验证事件时,我们将调用 updateUserData() 方法。此方法可使 UserData 对象保持同步。UserData.isSignedIn 属性是 LiveData,这意味着当值更改时,订阅此属性的观察者将收到通知。我们使用此机制来自动刷新用户界面。

我们还添加了代码以在应用程序启动时检查以前的身份验证状态。当应用程序启动时,它会检查 Cognito 会话是否已存在,并相应地更新 UserData。

在 Backend.initialize() 中,在 try/catch 块之后和 return 语句之前添加以下代码

// in Backend.initialize() function, after the try/catch block but before the return statement 





Log.i(TAG, "registering hub event")





// listen to auth event


Amplify.Hub.subscribe(HubChannel.AUTH)  hubEvent: HubEvent<*> ->





    when (hubEvent.name) 


        InitializationStatus.SUCCEEDED.toString() -> 


            Log.i(TAG, "Amplify successfully initialized")


        


        InitializationStatus.FAILED.toString() -> 


            Log.i(TAG, "Amplify initialization failed")


        


        else -> 


            when (AuthChannelEventName.valueOf(hubEvent.name)) 


                AuthChannelEventName.SIGNED_IN -> 


                    updateUserData(true)


                    Log.i(TAG, "HUB : SIGNED_IN")


                


                AuthChannelEventName.SIGNED_OUT -> 


                    updateUserData(false)


                    Log.i(TAG, "HUB : SIGNED_OUT")


                


                else -> Log.i(TAG, """HUB EVENT:$hubEvent.name""")


            


        


    








Log.i(TAG, "retrieving session status")





// is user already authenticated (from a previous execution) ?


Amplify.Auth.fetchAuthSession(


     result ->


        Log.i(TAG, result.toString())


        val cognitoAuthSession = result as AWSCognitoAuthSession


        // update UI


        this.updateUserData(cognitoAuthSession.isSignedIn)


        when (cognitoAuthSession.identityId.type) 


            AuthSessionResult.Type.SUCCESS ->  Log.i(TAG, "IdentityId: " + cognitoAuthSession.identityId.value)


            AuthSessionResult.Type.FAILURE -> Log.i(TAG, "IdentityId not present because: " + cognitoAuthSession.identityId.error.toString())


        


    ,


     error -> Log.i(TAG, error.toString()) 


)

要验证一切是否都按预期运行,请构建项目。单击 Build菜单,并选择 Make Project,或者,在 Mac 上按 ⌘F9。应该不会出现错误。

c.更新用户界面代码

代码中的最后一个更改与用户界面相关,我们将 FloatingActionButton 添加到主要活动中。

在“res/layout”下,打开 activity_main.xml,并将现有的 FloatingActionButton 替换为以下内容:

<com.google.android.material.floatingactionbutton.FloatingActionButton


    android:id="@+id/fabAuth"


    android:layout_width="wrap_content"


    android:layout_height="wrap_content"


    android:layout_alignParentRight="true"


    android:layout_gravity="bottom|end"


    android:layout_margin="@dimen/fab_margin"


    android:src="@drawable/ic_baseline_lock"


    app:fabCustomSize="60dp"


    app:fabSize="auto"


    />

在“res/drawable”下添加一个锁状图标。右键单击“drawable”,选择 New,然后选择 Vector Asset。从 Clilp Art 中选择锁状图标,然后输入 ic_baseline_lock(不含 _24)作为名称,并从 Clip Art 中选择闭合的锁状图标。单击 Next,然后单击 Finish

对打开的锁状图标重复相同的操作。

执行完以上操作后,您的“drawable”目录下应具有以下文件:

现在,在代码中链接新创建的按钮。在 java/com.example.androidgettingstarted/ 下,打开 MainActivity.kt 并添加以下代码。

// anywhere in the MainActivity class


private fun setupAuthButton(userData: UserData) 





    // register a click listener


    fabAuth.setOnClickListener  view ->





        val authButton = view as FloatingActionButton





        if (userData.isSignedIn.value!!) 


            authButton.setImageResource(R.drawable.ic_baseline_lock_open)


            Backend.signOut()


         else 


            authButton.setImageResource(R.drawable.ic_baseline_lock_open)


            Backend.signIn(this)


        


    



还是在 MainActivity 中,在 onCreate() 方法的末尾添加以下代码

setupAuthButton(UserData)





UserData.isSignedIn.observe(this, Observer<Boolean>  isSignedUp ->


    // update UI


    Log.i(TAG, "isSignedIn changed : $isSignedUp")





    if (isSignedUp) 


        fabAuth.setImageResource(R.drawable.ic_baseline_lock_open)


     else 


        fabAuth.setImageResource(R.drawable.ic_baseline_lock)


    


)

以上代码会针对 Userdata.isSignedIn 值注册观察者。当 isSignedIn 值更改时调用闭包。现在,我们只是更改锁状图标:当用户通过身份验证时为打开的锁,当用户没有会话时为闭合的锁。

要验证一切是否都按预期运行,请构建项目。单击 Build 菜单,并选择 Make Project,或者,在 Mac 上按 ⌘F9。应该不会出现错误。

d.更新 AndroidManifest.xml 和 MainActivity

最后,我们必须确保在 Cognito 托管用户界面提供的 Web 身份验证序列结束时启动我们的应用程序。我们在清单文件中添加一个新的活动。当接收到 gettingstarted URI 方案时,将调用该活动。

在 Android Studio 中的“manifests”下,打开 AndroidManifest.xml,并在应用程序元素中添加以下活动。

    <activity


android:name="com.amazonaws.mobileconnectors.cognitoauth.activities.CustomTabsRedirectActivity">


        <intent-filter>


            <action android:name="android.intent.action.VIEW" />





            <category android:name="android.intent.category.DEFAULT" />


            <category android:name="android.intent.category.BROWSABLE" />





            <data android:scheme="gettingstarted" />


        </intent-filter>


    </activity>

在 java/com.example.androidgettingstarted/ 下,打开 MainActivity.kt 并在类中的任意位置添加以下代码。

// MainActivity.kt


// receive the web redirect after authentication


override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) 


    super.onActivityResult(requestCode, resultCode, data)


    Backend.handleWebUISignInResponse(requestCode, resultCode, data)




在 java/com.example.androidgettingstarted/ 下,打开 Backend.kt 并在类中的任意位置添加以下代码。


// Backend.kt


// pass the data from web redirect to Amplify libs 


fun handleWebUISignInResponse(requestCode: Int, resultCode: Int, data: Intent?) 


    Log.d(TAG, "received requestCode : $requestCode and resultCode : $resultCode")


    if (requestCode == AWSCognitoAuthPlugin.WEB_UI_SIGN_IN_ACTIVITY_CODE) 


        Amplify.Auth.handleWebUISignInResponse(data)


    



e.构建和测试

要验证一切是否都按预期运行,请构建并运行项目。单击工具栏中的运行图标 ▶️,或按 ^ R。应该不会出现错误。应用程序将启动,且屏幕右下角会显示一个闭合的锁状浮动按钮。

以下是完整的注册流程。

4.添加 GraphQL API 和数据库

在此单元中,您将使用 Amplify CLI 和库配置和添加 GraphQL API 到您的应用程序中。

4.1简介

现在,我们已经创建并配置了带用户身份验证功能的应用程序。接下来,我们要在数据库中添加 API 以及“创建”、“读取”、“更新”、“删除”(CRUD) 操作。

在此单元中,您将使用 Amplify CLI 和库将 API 添加到您的应用程序中。您将创建的 API 是 GraphQL API,它利用 Amazon DynamoDB(NoSQL 数据库)支持的 Amazon AppSync(托管 GraphQL 服务)。有关 GraphQL 的介绍,请访问此页面

您将构建的应用程序是备注记录应用程序,用户可使用它创建、删除和列出备注。本示例将让您了解如何构建很多常见类型的 CRUD+L(创建、读取、更新、删除和列出)应用程序。

4.2实施

4.2.1创建GraphQL API服务和数据库

要创建 GraphQL API 及其后备数据库,请打开一个终端,然后从项目目录中执行此命令

amplify add api

初始化项目时选择的默认文本编辑器 (amplify init) 将使用预构建数据 schema 打开。

删除此 schema,并使用我们的应用程序 GraphQL schema 替换

type NoteData


@model


@auth (rules: [  allow: owner  ]) 


    id: ID!


    name: String!


    description: String


    image: String



数据模型由一个类 NoteData 和 4 个属性组成:ID 和名称是必填项,描述和图像是选填字符串。

@model 转换器指示我们需要创建数据库来存储数据。

@auth 转换器添加了身份验证规则,以允许访问此数据。对于此项目,我们希望仅 NoteData 的拥有者有访问它们的权限。

完成后,请不要忘记保存,然后返回您的终端以告知 Amplify CLI 您已完成。

? Press enter to continue, press enter.

几秒钟后,您应该会看到一条成功消息:

GraphQL schema compiled successfully.

4.2.2生成客户端代码

根据我们刚刚创建的 GraphQL 数据模型定义,Amplify 会生成客户端代码(即 Swift 代码)以代表我们应用程序中的数据。

要生成代码,请在终端执行以下命令:

amplify codegen models

这将在 java/com/amplifyframework.datastore.generated.model 目录中创建 Java 文件,如以下情况所示:

➜  Android Getting Started git:(master) ✗ ls -al app/src/main/java/com/amplifyframework/datastore/generated/model 


total 24


drwxr-xr-x  4 stormacq  admin   128 Oct  7 15:27 .


drwxr-xr-x  3 stormacq  admin    96 Oct  7 15:27 ..


-rw-r--r--  1 stormacq  admin  1412 Oct  7 15:27 AmplifyModelProvider.java


-rw-r--r--  1 stormacq  admin  7153 Oct  7 15:27 NoteData.java

这些文件会自动导入到您的项目中。

4.2.2部署API服务和数据库

要部署我们刚刚创建的后端 API 和数据库,请转至您的终端,然后执行命令

amplify push


# press Y when asked to continue





? Are you sure you want to continue? accept the default Y and press enter


? Do you want to generate code for your newly created GraphQL API type N and press enter

几分钟后,您应该会看到一条成功消息:

✔ All resources are updated in the cloud

GraphQL endpoint: https://yourid.appsync-api.eu-central-1.amazonaws.com/graphql

4.2.4将API客户端库添加到Android Studio项目

在转到此代码之前,请先返回 Android Studio,将以下依赖关系连同您之前添加的其他“amplifyframework”实现一起添加到您的单元的 build.gradle,然后在看到提示时单击 Sync Now

dependencies 


    implementation 'com.amplifyframework:aws-api:1.4.0'


    implementation 'com.amplifyframework:aws-auth-cognito:1.4.0'



4.2.5在运行时初始化Amplify库

打开 Backend.kt,然后在 initialize() 方法的 Amplify 初始化序列中添加一行。完整的尝试/捕获代码块应如下所示:

try 


    Amplify.addPlugin(AWSCognitoAuthPlugin())


    Amplify.addPlugin(AWSApiPlugin())


    Amplify.configure(applicationContext)





    Log.i(TAG, "Initialized Amplify")


 catch (e: AmplifyException) 


    Log.e(TAG, "Could not initialize Amplify", e)



4.2.6在GraphQL数据模型和应用程序模型之间添加桥接

我们的项目已经有一个数据模型来表示备注。在此教程中,我们将继续使用该模型,并提供一种将 NoteData 转换为备注的简单方法。打开 UserData.kt 并添加两个组件:一个动态属性,从 UserData.Note 返回 NoteData 对象;一个相反静态方法,接收 API NoteData 并返回 Userdata.Note。

在数据类 Note 中,添加以下内容:

// return an API NoteData from this Note object


val data : NoteData


    get() = NoteData.builder()


            .name(this.name)


            .description(this.description)


            .image(this.imageName)


            .id(this.id)


            .build()





// static function to create a Note from a NoteData API object


companion object 


    fun from(noteData : NoteData) : Note 


        val result = Note(noteData.id, noteData.name, noteData.description, noteData.image)


        // some additional code will come here later


        return result


    


     

确保通过生成的代码导入 NoteData 类。

4.2.7将API CRUD方法添加到后端类

我们添加 3 种方法来调用 API:一种查询 Note 的方法,一种创建新 Note 的方法,以及一种删除 Note 的方法。请注意,这些方法适用于应用程序数据模型 (Note),以便通过用户界面轻松交互。这些方法可以透明地将 Note 转换为 GraphQL 的 NoteData 对象。

打开 Backend.kt 文件,然后在后端类末尾添加以下代码段:

fun queryNotes() 


    Log.i(TAG, "Querying notes")





    Amplify.API.query(


        ModelQuery.list(NoteData::class.java),


         response ->


            Log.i(TAG, "Queried")


            for (noteData in response.data) 


                Log.i(TAG, noteData.name)


                // TODO should add all the notes at once instead of one by one (each add triggers a UI refresh)


                UserData.addNote(UserData.Note.from(noteData))


            


        ,


         error -> Log.e(TAG, "Query failure", error) 


    )








fun createNote(note : UserData.Note) 


    Log.i(TAG, "Creating notes")





    Amplify.API.mutate(


        ModelMutation.create(note.data),


         response ->


            Log.i(TAG, "Created")


            if (response.hasErrors()) 


                Log.e(TAG, response.errors.first().message)


             else 


                Log.i(TAG, "Created Note with id: " + response.data.id)


            


        ,


         error -> Log.e(TAG, "Create failed", error) 


    )








fun deleteNote(note : UserData.Note?) 





    if (note == null) return





    Log.i(TAG, "Deleting note $note")





    Amplify.API.mutate(


        ModelMutation.delete(note.data),


         response ->


            Log.i(TAG, "Deleted")


            if (response.hasErrors()) 


                Log.e(TAG, response.errors.first().message)


             else 


                Log.i(TAG, "Deleted Note $response")


            


        ,


         error -> Log.e(TAG, "Delete failed", error) 


    )




确保通过生成的代码导入 ModelQuery、ModelMutation 和 NoteData 类。

最后,我们必须在应用程序启动时调用此 API,以查询当前登录用户的 Note 列表。

在 Backend.kt 文件中,更新 updateUserData(withSignInStatus: Boolean) 方法,使其看起来类似以下内容:


// change our internal state and query list of notes 


private fun updateUserData(withSignedInStatus : Boolean) 


    UserData.setSignedIn(withSignedInStatus)





    val notes = UserData.notes().value


    val isEmpty = notes?.isEmpty() ?: false





    // query notes when signed in and we do not have Notes yet


    if (withSignedInStatus && isEmpty ) 


        this.queryNotes()


     else 


        UserData.resetNotes()


    



现在,只需创建一个用户界面即可创建新 Note 和从列表中删除 Note。

4.2.8添加“Edit"按钮以添加备注

现在,后端和数据模型已到位,本节的最后一步是让用户创建新的 Note 然后将其删除。

a.在 Android Studio 中的 res/layout 下,创建一个新布局:

右键单击 layout,选择“New”,然后选择 Layout Resource File。将此文件命名为 activity_add_note 并接受所有其他默认值。单击 OK

打开刚刚创建的文件 activity_add_note,然后通过粘贴以下内容替换所生成的代码:

<?xml version="1.0" encoding="utf-8"?>


<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"


    xmlns:app="http://schemas.android.com/apk/res-auto"


    android:layout_width="match_parent"


    android:layout_height="match_parent"


    android:fitsSystemWindows="true"


    android:fillViewport="true">





    <LinearLayout


        android:layout_width="match_parent"


        android:layout_height="wrap_content"


        android:orientation="vertical"


        android:padding="8dp">





        <TextView


            android:id="@+id/title"


            android:layout_width="wrap_content"


            android:layout_height="wrap_content"


            android:layout_marginTop="8dp"


            android:text="Create a New Note"


            android:textSize="10pt" />





        <EditText


            android:id="@+id/name"


            android:layout_width="fill_parent"


            android:layout_height="wrap_content"


            android:layout_marginTop="8dp"


            android:hint="name"


            android:inputType="text"


            android:lines="5" />





        <EditText


            android:id="@+id/description"


            android:layout_width="fill_parent"


            android:layout_height="wrap_content"


            android:layout_marginBottom="8dp"


            android:hint="description"


            android:inputType="textMultiLine"


            android:lines="3" />





        <Space


            android:layout_width="match_parent"


            android:layout_height="0dp"


            android:layout_weight="1" />





        <Button


            android:id="@+id/addNote"


            style="?android:attr/buttonStyleSmall"


            android:layout_width="fill_parent"


            android:layout_height="wrap_c

以上是关于使用 Amazon Amplify快速创建简单的 Android 应用程序的主要内容,如果未能解决你的问题,请参考以下文章

如何在没有 Amplify 的情况下使用 Amazon Cognito

基于 Amazon Amplify 构建自己的首个 iOS 应用程序

基于 Amazon Amplify 构建自己的首个 iOS 应用程序

基于 Amazon Amplify 构建自己的首个 iOS 应用程序

基于 Amazon Amplify 构建自己的首个 iOS 应用程序

AWS Amplify 和 amazon-cognito-identity-js 的区别?