Swift で AWS S3 に直接ファイルアップロード


AWS 弱者からするとなかなか面倒だったので手順をまとめました。
Objective-C でも殆ど同じ手順で同じ事が出来ると思います。
全部 parse.com が終わってしまうのが悪い。

## 前提

AWS のアカウントは所持している物とする。
リージョンは東京を利用する。
ライブラリの導入には cocoapods を利用する。

## 手順

1. Cognito で Federated Identity を作る
2. IAM の Role に S3 の設定を追加する
3. S3 に bucket を作成する
4. プロジェクト側に必要な設定をする
5. 適当なコードを書く

## Cognito で Federated Identity を作る

https://ap-northeast-1.console.aws.amazon.com/cognito/create/

上記のURLにアクセスし、Identity pool name を入力し、Unauthenticated identities の Enable access to unauthenticated identities にチェックを入れて「Create pool」ボタンを押せば Identity pool が作成されます。

## IAM へのアクセス許可とロールの設定

Create pool すると、次の画面で IAM へのアクセス許可を確認する画面が表示され、「詳細を表示」すると、IAM へ追加されるロールについて確認することができます。
ロール名に Cognito_\<Identiry pool name\>Unauth_Role と入っている方のポリシードキュメントを編集してこの Identity pool を利用した場合の S3 への操作許可を追加します。

今回はファイルのアップロードのみが目的なので以下のように編集しました。

``` json:role

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "mobileanalytics:PutEvents",
                "cognito-sync:*",
                "s3:PutObject*"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

```

細かく調整したい場合は、[IAM Policy Simulator](https://policysim.aws.amazon.com/home/index.jsp#roles) を参考にしながらロールを編集していけば良いと思います。

最後に「許可」のボタンを押せば Cognito と IAM に関する設定は完了です。
次の画面で各種プラットフォーム上で Cognito を使い始めるときに必要なコードを確認することが出来るので iOS-Swift を選択して以下の部分をどこかに保存しておきましょう。

``` swift:Cognito

let credentialsProvider = AWSCognitoCredentialsProvider(regionType:.APNortheast1,
   identityPoolId:"Identity Pool Id")

let configuration = AWSServiceConfiguration(region:.APNortheast1, credentialsProvider:credentialsProvider)

AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = configuration

```

## S3 に bucket を作成する

https://console.aws.amazon.com/s3/

上記のURLにアクセスし「バケットを作成」ボタンを押し、バケット名とリージョンを選択する事で新しいバケットを作成することが出来ます。
バケット名はあとで使います。

## プロジェクト側に必要な設定をする

### Podfile を編集する

Podfile がプロジェクトのルートディレクトリ上に作成されていない場合は事前に ```pod init``` しておく。

下記二つの pod を Podfile の必要な箇所に追記して状況にあわせて ``` pod install ``` か ``` pod update ``` を行う。（ use_frameworks! がコメントアウトされている場合はそれを外しておくこと）

``` ruby:Podfile 

pod 'AWSS3'
pod 'AWSCognito'

```

### 一度ビルドしておく

念のためビルドが通るかをこの時点で確認しておく。
.xcworkspace を開いてビルドしてみる。

## 適当なコードを書く

### AWSServiceManager への初期設定を行う

AppDelegate にアクセス許可の部分で取って置いたコードを貼り付ける。

``` swift:AppDelegate

import UIKit
import AWSCognito

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        let credentialsProvider = AWSCognitoCredentialsProvider(regionType: .APNortheast1,
            identityPoolId: "Identity Pool Id")
        let configuration = AWSServiceConfiguration(region: .APNortheast1, credentialsProvider: credentialsProvider)
        AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = configuration
        return true
    }

}

```

### ファイルの作成とアップロード

とりあえず、ボタンが押されたらテキストファイルを S3 にあげるサンプルを載せておきます、YOUR BUCKET NAME には s3 で自分で設定したバケット名を入れてください。エラー処理等は簡略化しているので、ドキュメントを読むか [aws の公開しているサンプル](https://github.com/awslabs/aws-sdk-ios-samples)を参考にすると良いと思います。

``` swift:Sample

@IBAction func uploadTextFile() {
    let docDir = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as String
    let text = "Upload File."
    let fileName = "test.txt"
    let filePath = "\(docDir)/\(fileName)"
    try! text.writeToFile(filePath, atomically: true, encoding: NSUTF8StringEncoding)
    let transferManager = AWSS3TransferManager.defaultS3TransferManager()

    let uploadRequest = AWSS3TransferManagerUploadRequest()
    uploadRequest.bucket = "YOUR BUCKET NAME"
    uploadRequest.key = "sample.txt"
    uploadRequest.body = NSURL(string: "file://\(filePath)")
    uploadRequest.ACL = .PublicRead
    uploadRequest.contentType = "text/plain"

    transferManager.upload(uploadRequest).continueWithBlock { (task: AWSTask) -> AnyObject? in
        if task.error == nil && task.exception == nil {
            print("success")
        } else {
            print("fail")
        }
        return nil
    }

}

```

上記のコードを実行したあと、S3 の管理画面で Upload File. という内容の sample.txt がアップロードされていれば成功です。
AWSS3TransferManagerUploadRequest のプロパティに設定する事で、アップロードされたファイルのアクセス許可等の設定を変更することが出来るので、色々変更してどうなるのかを検証してみると良いと思います。