본문 바로가기
Cloud/Amazon Web Service

AWS Amplify 로 iOS 풀스택 Todo 앱 개발하기

by HaningYa 2020. 9. 3.
728x90

이 글은 AWS의 협찬을 받았으면 좋겠습니다.

AWS Amplify는

모바일 및 프론트 웹 개발자가 AWS에서 구동되는 풀스택 앱을 개발할 수 있게 도와주는 서비스 이다.

장점으로는

  • 혁신적인 앱 개발: Amplify Library를 통해 Auth, AI/ML 등을 단 몇 줄의 코드로 개발할 수 있다.
  • 몇 분만에 백엔드 구성: AWS S3나 Amazon Congito와 같은 AWS 서비스를 사용하여 회원가입, 스토리지, API 등의 백엔드를 자동으로 구성할 수 있다. 특히 Amplify CLI를 통해 간단한 명령으로 앱을 위한 백엔드를 개인화 할 수 있다.
  • 편리한 배포 및 확장: AWS Amplify콘솔에서 비즈니스 성장에 따라 가용성을 수정할 수 있다. 몇 분 만에 확장 가능한 정적 웹 사이트 및 웹앱 배포가 가능하다.

자세한 내용은 서비스 페이지에서 확인

 

모바일 및 웹 앱을 빠르게 개발 – AWS Amplify – Amazon Web Services

“최신 사이드 프로젝트, @snapgig, 기가 막힌 경제 마켓플레이스 개시! @AWSAmplify CLI/Console을 활용해 복잡한 백엔드를 구축하고 조직화된 배포, #React/#GraphQL, 인증, 채팅,이미지 업로드 등을 훨씬 쉽�

aws.amazon.com


Amplify 를 이용해 iOS Todo앱의 백엔드를 구성해볼 것 이다.

대략적인 순서는 이렇다.

  1. AWS Amplify CLI 설치
  2. iOS Todo Xcode 프로젝트 생성
  3. 프로젝트 빌드에 Amplify 세팅
  4. Todo Project 에서 모델 파일 생성
  5. AWS Amplify 프레임워크 Todo Project 에 integration
  6. 해당 프로젝트 Cloud 에 연동
  7. Todo List UI 구성 및 앱 완성

1. AWS Amplify CLI 설치 (Mac 환경)

Node와 NPM 이 설치되어 있어야 한다. 

  • Node 버전 10.x 이상
  • npm 버전 6.x 이상

버전확인은 터미널에서 node -v, npm -v 로 확인할 수 있다.

버전확인

설치 안된 사람은 이 포스팅 참고

 

맥북 터미널에서 brew 이용해서 node, npm 설치하기

맥북에 node를 설치할 때 nodejs.org에서 설치파일을 다운로드 받아서 설치하는 것이 일반적입니다. 하지만 이렇게 설치하면 -g 옵션으로 global로 설치 할때 매번 su로 해줘야하는 불편함이 있습니다

ftdev.tistory.com


이제 amplify cli 설치해 보겠다.

터미널에서 코드 입력

npm install -g @aws-amplify/cli

설치완료


1-2. CLI Configuration

터미널에서 아래 코드 입력

amplify configure

configuration이 시작되면 자동으로 AWS Console이 열린다.

여기서 AWS에 로그인하고 터미널로 돌아와 Enter 를 누른다.

AWS console
enter

 

그럼 Region 을 선택하라고 나오는데 나는 서울리전 이므로 ap-northeast-2 를 선택한다.

서울 리전을 선택한다.

그 후 IAM username 을 입력하라고 한다. IAM 은 일종의 admin 권한이 아닌 제한된 권한을 가지는 유저이다.

원하는 이름으로 작성하면 작성된 이름으로 AWS IAM Dashboard 가 뜬다.

유저이름은 맘에 드는거 아무거나
터미널에서 입력된 username 이 미리 작성되 있다.

따로 건들이지 않고 Next로 하여 새로운 유저를 만든다.

IAM 유저 생성완료

Access Key 와 Secret Access Key 가 부여되는데 Secret Access Key 의 경우는 한번밖에 발급이 안되기 때문에 .csv 다운로드로 소중하게 간직한다.

그리고 Access Key 와 access key 를 복사해 터미널로 돌아와 붙여넣는다.

accesskey 입력
secretkey 입력

 

profile name 은 default로 설정한다.

추가 완료

Amplify CLI 준비 끝


2. Todo Xcode 프로젝트 생성

xcode 에서 일반적인 방법으로 프로젝트를 하나 생성한다. (SingleView App)

아무것도 안되있는 빈 프로젝트

iOS 프로젝트에 Amplify 프레임워크를 적용하려면 Cocoapod 을 사용해야 한다.

[코코아팟 모르는 사람은 아랫글 참조]

 

왕 초보를 위한 CocoaPods(코코아팟) 사용법 (Xcode와 연동)

안녕하세요! 오늘은 CocoaPod사용법에 대해 알려드릴려고해요 :) 저는 CocoaPod 처음에 시작할 때 뭐가 뭔지 몰라서 정말 하나도 몰라서 진짜 어려운거구나...라고 생각했었어요. 하지만 한번 배워 놓

zeddios.tistory.com

일반적으로 pod 설정하듯이 해당 프로젝트 디렉토리로 가서 

pod init

해준다.

Podfile 내용은

Podfile

 pod 'Amplify'
 pod 'Amplify/Tools'
 pod 'AmplifyPlugins/AWSAPIPlugin'
 pod 'AmplifyPlugins/AWSDataStorePlugin'

이렇게 채우고

이런 식으로 진행

pod install --repo-update

를 해주면 막 좌좌작 깔린다.

다 설치된 결과


3. 프로젝트 빌드에 Amplify 세팅

xcode 프로젝트를 열되 밑에 cocoapod 적용된 workspace 로 연다.

Todo Project 에서 Target -> Build Phase 로 들어간다.

build phase

여기서 새로운 Run Script Phase 를 + 버튼을 통해 만든다.

Run Script의 순서를 Compile Sources 전 단계로 옮긴다. (드래그 하면 이동됨)

Run Script 탭을 열러 shell script 에 아래의 코드를 작성한다.

"${PODS_ROOT}/AmplifyTools/amplify-tools.sh"

 

Build Phase 에 추가가 완료되었다. 이제 프로젝트를 빌드해보면 Amplify tool도 같이 빌드되는 걸 볼 수 있다.

만약 처음 Build 하는 경우면 프로젝트 디렉토리에 새로운 파일들이 생긴걸 볼 수 있다.

  • amplifyConfig Folder: 여러가지 config 파일과 미리 만들어진 샘플 파일들이 있는 디렉토리이다.
  • amplifytools.xcconfig: amplify tool의 동작을 설정하는 config 파일이다.
  • amplifyconfiguration.json: 프로젝트에 추가되어 번들과 함께 전달된다. amplify libraries 가 필요로 한다.
  • awsconfiguration.json: 프로젝트에 추가되어 번들과 함께 전달된다. amplify libraries 가 필요로 한다.

4. Todo Project 에서 모델 파일 생성

프로젝트 및 amplify 세팅은 끝났다. 다음은 앱이 저장할 데이터 모델을 만드는 것이다.

Amplify DataStore는 지금 만들 모델을 사용하여 추가적인 코드 작성없이 backend api에 local device 데이터를 동기화 시킨다.

이 모델을은 GraphQL이라는 스키마를 사용할 것이다. 

[GraphQL은 Facebook이 만든 데이터 질의어 이다.]

 

GraphQL: A query language for APIs.

GraphQL provides a complete description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.

graphql.org

 

AmplifyConfig 에 있는 schema.graphql 파일을 연다.

원래 있던 코드를 아래의 코드로 수정한다.

enum Priority {
  LOW
  NORMAL
  HIGH
}

type Todo @model {
  id: ID!
  name: String!
  priority: Priority
  description: String
}

모델에 대해 간단히 설명하면

  • id: 자동으로 만들어지는 identifier 역할을 하는 필드
  • name: 필수 문자열 필드로 Todo 의 제목
  • priority: optional enumeration 타입으로 Todo 의 우선순위를 작성하는 필드이다.
  • description: Todo의 설명으로 optional String 필드이다.

그다음 이 모델을 위한 class 를 생성한다.

amplifytools.xcconfig 파일에서 modelgen=true 로 바꿔준다.

그러고 나서 프로젝트 빌드(cmd + b) 를 하면 모델에 관한 새로운 클래스들이 생성된 것을 볼 수 있다.


4. AWS Amplify 프레임워크 Todo Project 에 integration

생성된 모델을 create, update, query, delete 해볼 것이다. 그러기 위해 DataStore를 초기화 해서 Todo items를 다뤄볼 것 이다.

먼저 AppDelegate 에서 Amplify 와 DataStore를 추가한다.

import Amplify
import AmplifyPlugins

그리고 application(_ Didfinishlaunchingwithoptions:) 에 아래 코드를 작성한다.

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        let dataStorePlugin = AWSDataStorePlugin(modelRegistration: AmplifyModels())
        do {
           try Amplify.add(plugin:dataStorePlugin)
           try Amplify.configure()
           print("Initialized Amplify");
        } catch {
           print("Could not initialize Amplify: \(error)")
        }
        
        return true
    }

그리고 Build 하고 실행하면 Xcode Console 에서 

Initialized Amplify 

추가적으로 log level의 단계를 바꾸고 싶다면 Amplify.Logging.Loglevel 변수를 사용하면된다.

예를들어 AppDelegate 의 didFinishLaunchingWithOptions에 해당 변수를 .info 로 바꾸면

logLevel 을 info로

실행했을 때 좀더 상세한 로그를 볼 수 있다.

상세한 로그가 출력된다.

이제 실제 Todo List 에 대한 메서드를 작성해 보자

ViewController 에 추가하면 된다.

DataStore 에 Todo 추가하는 코드

    private func addTodo(_ title: String, _ priority: Priority,_ description: String){
        let item = Todo(id: UUID().uuidString, name: title, priority: priority, description: description)
        Amplify.DataStore.save(item) { result in
            switch result {
            case .success(let savedItem):
                print("Saved Item: \(savedItem.name)")
            case .failure(let error):
                print("Could not save item to dataStore: \(error)")
            }
        }
    }

DataStore 에 저장된 Todo 를 가져오는 코드

    private func queryTodo() {
        Amplify.DataStore.query(Todo.self, completion: { result in
            switch(result) {
            case .success(let todos):
                for todo in todos {
                    print("==== Todo ====")
                    print("Name: \(todo.name)")
                    if let priority = todo.priority {
                        print("Priority: \(priority)")
                    }
                    if let description = todo.description {
                        print("Description: \(description)")
                    }
                }
            case .failure(let error):
                print("Could not query DataStore: \(error)")
            }
        })
    }

쿼리할 땐 몇가지 filter 옵션이 있다.

해당 옵션을 쓰려면 아래와 같이 where 문만 추가하면 된다.

Amplify.DataStore.query(Todo.self,
                       where: Todo.keys.priority.eq(Priority.high.rawValue),
                       completion: { result in
                       ...생략

DataStore 에 저장된 Todo Update 하는 코드

    private func updateTodo(_ title: String) {
        Amplify.DataStore.query(Todo.self,
            where: Todo.keys.name.eq(title),
            completion: {
                result in
                switch (result) {
                    case.success(let todos):
                        guard todos.count == 1,
                            var updatedTodo = todos.first
                        else {
                            print("Did not find exactly one todo, bailing")
                            return
                        }
                        updatedTodo.name = "File quarterly taxes"
                        Amplify.DataStore.save(updatedTodo,
                            completion: {
                                result in
                                switch (result) {
                                    case.success(let savedTodo):
                                        print("Updated item: \(savedTodo.name )")
                                    case.failure(let error):
                                        print("Could not update data in Datastore: \(error)")
                                }
                            })
                    case.failure(let error):
                        print("Could not query DataStore: \(error)")
                }
            })
    }

DataStore 에 저장된 Todo  Delete 하는 코드

    private func deleteTodo(_ title: String) {
        Amplify.DataStore.query(Todo.self,
            where: Todo.keys.name.eq("title"),
            completion: {
                result in
                switch (result) {
                    case.success(let todos):
                        guard todos.count == 1,
                            let toDeleteTodo = todos.first
                        else {
                            print("Did not find exactly one todo, bailing")
                            return
                        }
                        Amplify.DataStore.delete(toDeleteTodo,
                            completion: {
                                result in
                                switch (result) {
                                    case.success:
                                        print("Deleted item: \(toDeleteTodo.name)")
                                    case.failure(let error):
                                        print("Could not update data in Datastore: \(error)")
                                }
                            })
                    case.failure(let error):
                        print("Could not query DataStore: \(error)")
                }
            })
    }

7. Todo 프로젝트 AWS 에 연동

DataStore 를 통해 local 하게 데이터를 유지하는 것 까지 작성했다. 다음 단계는 해당 데이터를 클라우드와 연동하는 것 이다.

amplifytools.xcconfig 파일에서 push 를 true 로 바꿔준다.

그리고 빌드를 하게되면 amplify tool이 프로젝트에 설정된 configuration을 백엔드로 push 해준다.

몇분정도 걸릴 수 있고 xcode 로딩바에서 진행상황을 볼 수 있다.

끝나면 subcription을 추가해야 한다.

subscription 하는 이유는 백엔드에서 값이 Mutate 되었을때 로컬 DataStore 을 업데이트 해주기 위해서 이다.

(여기서 말하는 subscription은 Rx 에서 쓰이는 subscription인 것 같다.)

AppDelegate 에서 아까 작성한 Amplify init 코드에 apiPlugin을 추가하여 수정해야 한다.

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        
        Amplify.Logging.logLevel = .info
        let apiPlugin = AWSAPIPlugin(modelRegistration: AmplifyModels())
        let dataStorePlugin = AWSDataStorePlugin(modelRegistration: AmplifyModels())
        do {
           try Amplify.add(plugin:apiPlugin)
           try Amplify.add(plugin:dataStorePlugin)
           try Amplify.configure()
           print("Initialized Amplify");
        } catch {
           print("Could not initialize Amplify: \(error)")
        }
        
        return true
    }

Subscribe를 Combine 으로 한다. ViewController 로 돌아와 아래 코드를 작성해 준다.

@State var todoSubscription: AnyCancellable?
func subscribeTodos() {
   self.todoSubscription
       = Amplify.DataStore.publisher(for: Todo.self)
           .sink(receiveCompletion: { completion in
               print("Subscription has been completed: \(completion)")
           }, receiveValue: { mutationEvent in
               print("Subscription got this value: \(mutationEvent)")
           })
}

그리고 Todo 정보 업데이트가 필요한 곳에서 함수를 호출한다. (나는 viewDidLoad 에서 호출)

이제 잘 백엔드와 잘 동작되는지 테스트 해보자

Xcode 프로젝트가 있는 경로에서 터미널을 통해 아래 명령어 입력한다.

amplify console api

GraphQL 을 선택한다.

그럼 AWS AppSync Console 웹이 뜬다.

여기서 쿼리를 던질 수 있다.

어떤 Todo 가 있는지 쿼리

 query GetTodos {
     listTodos {
         items {
             id
             name
             description
             _deleted
         }
     }
 }

나는 아직 아무것도 추가하지 않아 빈 배열이 리턴된다.

Console 에서 Todo 아이템 추가쿼리

 mutation CreateTodo {
     createTodo(
         input: {
         name: "Tidy up the office",
         description: "Organize books, vacuum, take out the trash",
         priority: NORMAL
         }
     ) {
         id,
         name,
         description,
         priority,
         _version,
         _lastChangedAt,
     }
 }

해당 쿼리를 입력한 뒤 앱을 다시켜면 subscribeTodos의 completion을 통해 정보가 받아질 것 이다.

추가된 Todo Item 이 받아와 진다.


7. Todo List UI 구성 및 앱 완성

일단 간단하게 화면 구성하고 몇가지 기능만 구현했다.

  • 할일 데이터 들고와서 TableView 뿌리기
  • 할일 데이터 웹에서 추가 및 삭제시 앱 새로고침 없이 데이터 갱신 (Combine)
  • 할일 데이터 앱에서 추가 및 삭제시 백엔드에 반영

[앞으로 구현해야 하는 기능]

  • 할일 검색
  • 할일 수정
  • 디자인 조금 수정

일단 완성된 앱 영상

이렇게 하고난 뒤 콘솔에서 쿼리 날려보면

데이터가 잘 들어가있는 걸 볼 수 있다.

{
  "data": {
    "listTodos": {
      "items": [
        {
          "id": "3E459A7F-DEB7-4412-A846-471C5AFA0691",
          "name": "할일추가 2예시",
          "description": "언제 삭제 검색 수정기능만드냐",
          "_deleted": null
        },
        {
          "id": "496e6d77-9a99-41aa-a932-fe33a1eca6f7",
          "name": "Tidy up the office",
          "description": "Organize books, vacuum, take out the trash",
          "_deleted": null
        },
        {
          "id": "98B171A7-FDD3-4913-B6E3-590187B78ABA",
          "name": "예시 할일 추가",
          "description": "이것은 할일 입니다",
          "_deleted": null
        },
        {
          "id": "d1662950-fbfe-4ec3-9910-b77422cacace",
          "name": "방금 추가한 할일",
          "description": "Organize books, vacuum, take out the trash",
          "_deleted": true
        },
        {
          "id": "c435f16f-d336-41e3-a726-9d46919352e1",
          "name": "Tidy up the office",
          "description": "Organize books, vacuum, take out the trash",
          "_deleted": null
        },
        {
          "id": "02E0A22C-353E-422A-874C-D677C290CD69",
          "name": "물론 앱에서도 추가하면",
          "description": "백엔드에서 변경사항 볼 수있음",
          "_deleted": null
        },
        {
          "id": "eb296ced-7cba-4678-8054-e86c00a4403c",
          "name": "subscription 과 콤바인으로 추가됨",
          "description": "Organize books, vacuum, take out the trash",
          "_deleted": true
        }
      ]
    }
  }
}

이 부분의 자세한 내용은 생략하고 Github 을 통해 전체 코드 공유한다.

 

KimTaeHyeong17/AWS-Amplify-iOS-Example

AWS Amplify 를 이용한 iOS 앱 예제. Contribute to KimTaeHyeong17/AWS-Amplify-iOS-Example development by creating an account on GitHub.

github.com


느낀점

iOS Native 개발자로써 Google의 Firebase 와 유사하다는 느낌이 들었다. 하지만 AWS GraphQL 과 같은 디비 뿐만이 아니라 REST API 까지 지원한다는 점에서 첫번째 차이점이 있었고 또한 AWS의 리소스를 사용하면서 AppSync 나 DynamoDB를 통해 확장이 가능한 백엔드를 구축할 수 있다는 점에서 장점이 있는 것 같다. 또한 AI/ML 과 같은 AWS 서비스를 쉽게 통합하여 구현할 수 있다는 점도 매력인 것 같다.

각종 AI/ML 카테고리

웹 개발자들에게 있어서는 Amplify CLI를 통해 웹앱 만들어 쉽게 배포하거나 풀스택 하이브리드앱도 지원한다는 점에서 좋을 것 같다.

다양한 프레임워크를 지원한다.


AWS Amplify vs Google Firebase

 

AWS Amplify vs Firebase | Back4App Blog

You will learn the differences between AWS Amplify and Google Firebase, and the benefits of each cloud platform.

blog.back4app.com

 

728x90

댓글