LoginSignup
31
32

More than 5 years have passed since last update.

Amazon Mobile SDK for iOSを使って感じたこととはまったこと

Posted at

2014年の7月にiOSなどのモバイル用に新しいAWS SDKが発表されました。
それが「AWS Mobile SDK」です。

今までもSDKは存在していたので、V2といったところです。

発表から半年ほど経っていますが、
このSDKを使う機会が最近ありましたので、
そのときのことをまとめてみました。

参考にしていた情報

AWS Mobile SDK関連

Cognito関連

V2の改善点

V2になることで大きく改善がされました。

個人的に以下の点がありがたいと思っています。

AWSリソースアクセスの認証処理が簡単に実装できるようになった

DynamoDBやS3といったAWSリソースにアクセスするために、
一時的な証明書を取得する必要があります。
今までは、そのキーを取得するために、
Token Vending Machine(TVM)とそれ用のクライアント処理を実装する必要がありました。
どちらもサンプルを参考にすればできるのですが、
アカウントの管理など自分達でやる必要もあるため正直かなり面倒でした。

ところが、今回「Cognito」という仕組みが出てきました。

クライアント側の実装のみで、簡単に一時的な証明書を取得できます。
さらに、新しいSDKは、
AWSリソースへのアクセス時には、その証明書を裏で取得してくれているので、
気にすることなくアクセスできます。

非同期処理

今までのSDKだと、自分たちで非同期処理を実装し、
値が取得できたらメインスレッドに戻すといったことが必要でした。

今回は、そういったことが不要になりました。
(正確には、Bolts Frameworkを使って非同期処理を書けるようにしている)

Bolts Frameworkについては以下を参照
iOS/Android対応 Boltsを使って非同期処理を統一的に書く

DynamoDBの呼び出し方が簡単になった (Object Mapper)

今までDynamoDBのAPI実行において、
リクエスト生成とレスポンスからモデルオブジェクトの生成が面倒でした。
今回から、AWSDynamoDBModelを継承したクラスを用意しておけば、
リクエスト生成やモデルオブジェクトの生成をObject Mapperがやってくれるので楽ちんです。

#import "AWSDynamoDBObjectMapper.h"
#import "DynamoDB.h"

@interface DDBUserProfileTableRow : AWSDynamoDBObjectModel <AWSDynamoDBModeling>

// カラム名をここで定義しておく
@property (nonatomic, strong) NSString *userId;
@property (nonatomic, strong) NSString *userName;
@property (nonatomic, strong) NSString *userPictUrl;
@property (nonatomic, strong) NSNumber *createDate;

@end
#import "DDBUserProfileTableRow.h"

@implementation DDBUserProfileTableRow

// テーブル名
+ (NSString *)dynamoDBTableName {
    return @"UserProfile";
}

// ハッシュキー
+ (NSString *)hashKeyAttribute {
    return  @"userId";
}

@end
// ユーザー情報取得
+ (void)loadUserProfileByUserId:(NSString *)userId
{
    [[[AWSDynamoDBObjectMapper defaultDynamoDBObjectMapper] load:[DDBUserProfileTableRow class]
                                                         hashKey:userId
                                                        rangeKey:nil]
     continueWithExecutor:[BFExecutor mainThreadExecutor] 
            withBlock:^id(BFTask *task) {
         // 非同期処理
         if (!task.error) {
             // 成功処理
             // データがセットされた状態モデルオブジェクトが取得できる
             DDBUserProfileTableRow *tableRow = (DDBUserProfileTableRow *)task.result;
             // もし、対象のレコードがない場合、モデルオブジェクトの全ての値にnilが入っている
         } else {
             // 失敗処理
         }
         return nil;
    }];

}

作ったもの

  • Facebookでログイン
  • DynamoDBにユーザー名とユーザー画像URLを保存
  • 自動ログイン
  • DynamoDBからユーザー名とユーザー画像URLを取得
  • ログアウト

はまったこと

リージョンがCognitoとDynamoDBで違い、Cognito Syncが使えない

Cogniteはまだ以下のリージョンしか対応していません
* US East (N. Virginia)
* EU (Ireland)

しかし、DynamoDBはTokyoリージョンだったりしますよね。
Cognitoが限られたリージョンのみだからか、
SDKはそれを想定した作りになっています。
以下のように
Cognitoとそれ以外のAWSサービスのリージョンを別で指定できるようになっています。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    // Cognitoを使った一時的な証明書を取得 (※Cognite用リージョンはここで指定)
    AWSCognitoCredentialsProvider *credentialsProvider
    = [AWSCognitoCredentialsProvider credentialsWithRegionType:CognitoRegionType
                                                identityPoolId:CognitoIdentityPoolId];

    // 自動的に発行されるIDを取得
    [[credentialsProvider getIdentityId] continueWithSuccessBlock:^id(BFTask *task) {
        NSLog(@"ID=%@", credentialsProvider.identityId);
        return nil;
    }];

    // AWSサービスにアクセスする場合の設定(※ Cognite以外のAWSサービス用リージョンはここで指定)
    [AWSServiceManager defaultServiceManager].defaultServiceConfiguration 
    = [AWSServiceConfiguration configurationWithRegion:DefaultServiceRegionType
                                   credentialsProvider:credentialsProvider];

    return YES;
}

ところが、なぜかCognitoデータ同期を使うときに、リージョンがその他AWSサービス用リージョンになっていました。

- (void)updateIsRegisteredUser:(BOOL)isRegisterdUser
{
    AWSCognito *syncClient = [AWSCognito defaultCognito];
    AWSCognitoDataset *dataset = [syncClient openOrCreateDataset:AWSCongniteDataSetKeyState];

    // 保存
    NSString *value = (isRegisterdUser) ? @"YES" : @"NO";
    [dataset setString:value forKey:AWSCongniteDataSetKeyStateIsRegisterd];

    // 同期
    [[dataset synchronize] continueWithBlock:^id(BFTask *task) {
        if (task.isCancelled) {
            DEBUG_LOG(@"同期キャンセル");
        } else if (task.error) {
            DEBUG_LOG(@"同期エラー: %@",task.error);
        } else {
            DEBUG_LOG(@"同期成功");
        }
        return nil;
    }];
}

そこで、AWSCognitoインスタンス生成時にリージョン指定をすることで解決しました。

- (void)updateIsRegisteredUser:(BOOL)isRegisterdUser
{
    // self.cognitoServiceConfigは事前にCognito用のリージョンを指定して作成したAWSServiceConfigurationです
    AWSCognito *syncClient = [[AWSCognito alloc] initWithConfiguration:self.cognitoServiceConfig];
    AWSCognitoDataset *dataset = [syncClient openOrCreateDataset:AWSCongniteDataSetKeyState];

    // 保存
    NSString *value = (isRegisterdUser) ? @"YES" : @"NO";
    [dataset setString:value forKey:AWSCongniteDataSetKeyStateIsRegisterd];

    // 同期
    [[dataset synchronize] continueWithBlock:^id(BFTask *task) {
        if (task.isCancelled) {
            DEBUG_LOG(@"同期キャンセル");
        } else if (task.error) {
            DEBUG_LOG(@"同期エラー: %@",task.error);
        } else {
            DEBUG_LOG(@"同期成功");
        }
        return nil;
    }];
}

Facebook認証がシミュレーターのSafariでネットワークエラー

Facebook認証でSafariが立ち上がるのですが、
その時に以下のような表示になることがありました。

iOS Simulator Screen Shot 2015.03.29 19.06.16.png

これは、シミュレーターの再起動で解消しました。

使ってみた感想

今回の新しいSDKにより、AWSを使ったアプリの実装がかなり楽になったと感じました。
いまいち分かっていないのが、Cognitoで保持できるデータです。
保持できる容量が限られているため、使い道が難しいなと感じています。

31
32
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
31
32