[cocos2d-x] iosでカメラやアルバムから取得した画像をaws s3にアップロードしてみる

vermuda小林です。アプリ担当だけどなんやかんや経理とか採用とかもやってます。
皆さんaws使ってますか？私は今の案件から使い始めましたけど開発に必要な部分の大半が揃ってて「これはいいものだ！」ってなってます。

今日はiosアプリからawsのs3にアップロードするのを書いてみます。
(cocos2d-xからネイティブ呼び出ししてるので純粋なios開発とはちょっと違うかも)


```

// まずはカメラ起動するところから

-(void)showUICameraPicker
{
    // カメラが使用可能かどうか判定する
    if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
        return;
    }
    
    // UIImagePickerControllerのインスタンスを生成
    UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
    
    // デリゲートを設定
    imagePickerController.delegate = self;
    
    // 画像の取得先をカメラに設定
    imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
    
    // 画像取得後に編集するかどうか（デフォルトはNO）
    imagePickerController.allowsEditing = YES;
    
    // 撮影画面をモーダルビューとして表示する
    [self presentViewController:imagePickerController animated:YES completion:nil];
}

// こっちはアルバム呼び出し

- (void)showUILibraryPicker
{
    // カメラが使用可能かどうか判定する
    if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
    {
        return;
    }
    
    // UIImagePickerControllerのインスタンスを生成
    UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
    
    // デリゲートを設定
    imagePickerController.delegate = self;
    
    // 画像の取得先をアルバムに設定
    imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
    
    // 画像取得後に編集するかどうか（デフォルトはNO）
    imagePickerController.allowsEditing = YES;
    
    // 画像選択画面をモーダルビューとして表示する
    [self presentViewController:imagePickerController animated:YES completion:nil];
}

// 画像選択完了後の処理(ここはコールバックで勝手に呼ばれます)
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    // モーダルビューを閉じる
    [self dismissViewControllerAnimated:YES completion:nil];
    UIImage* image = [info objectForKey:UIImagePickerControllerEditedImage];
    // 渡されてきた画像を一旦アルバム以外のフォルダに保存(これをしないとファイルパスがAsset Libraryのパスしか取れない)
    UIImageWriteToSavedPhotosAlbum(image, self, @selector(targetImage:didFinishSavingWithError:contextInfo:), NULL);
    NSURL* filePath;
    if ([info objectForKey:UIImagePickerControllerOriginalImage] != nil)
    {
        UIImage* tookImage = info[UIImagePickerControllerOriginalImage];
        NSString* imagePath = NSHomeDirectory();
        imagePath = [imagePath stringByAppendingPathComponent:@"Documents/face.png"];
        NSData* imageData = UIImagePNGRepresentation(tookImage);
        bool isSuccess = [imageData writeToFile:imagePath atomically:true];
        if (isSuccess)
        {
            filePath = [NSURL fileURLWithPath:imagePath isDirectory:false];
        }
    }
    // デリゲート先がちゃんと「sendPhoto」というメソッドを持っているか?
    if ([self.delegate respondsToSelector:@selector(sendPhoto: sendPath:)])
    {
        // getImageを呼び出す
        [self.delegate sendPhoto:image  sendPath:filePath];
    }
}
```

ここからいよいよs3アップロードの処理です。

```

// aws import
#import <AWSCore/AWSCore.h>
#import <AWSS3/AWSS3.h>

-(void)sendPhoto:(UIImage*)photo sendPath : (NSURL*) 
{
    native_plugin::NativeDelegate *pDelegate = (native_plugin::NativeDelegate*)object;
    if(pDelegate != NULL)
    {
        NSData *imgData = UIImagePNGRepresentation(photo);
        NSUInteger len = [imgData length];
        Byte *byteData = (Byte*)malloc(len);
        memcpy(byteData, [imgData bytes], len);
        
        // ファイル名の先頭の日時を作成
        NSDate *nowdate = [NSDate date];
        NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
        [formatter setDateFormat:@"yyyyMMddHHmmss"];
        NSString *datamoji = [formatter stringFromDate:nowdate];
        std::string dateStr = datamoji.UTF8String;
        
        // ファイル名の後半のランダム文字列を作成
        std::random_device rndDev;
        std::mt19937 mt = std::mt19937(rndDev());
        std::uniform_int_distribution<int> distribution( 0, INT_MAX ) ;
        std::string rndStr = StringUtils::format("%d", distribution(mt));
        
        // ファイル名を作成
        NSString* fileName = [[NSString alloc] initWithFormat:@"image/%s%s.jpg", dateStr.c_str(), rndStr.c_str()];
        AWSS3TransferManager *transferManager = [AWSS3TransferManager defaultS3TransferManager];
        AWSS3TransferManagerUploadRequest *uploadRequest = [AWSS3TransferManagerUploadRequest new];
        uploadRequest.bucket = @"bucketName";	//ここにS3のバケット名入れたげる
        uploadRequest.key = fileName;			//ファイル名
        uploadRequest.body = filePath;			//端末の画像ファイルパス
        uploadRequest.contentLength = [NSNumber numberWithUnsignedLongLong:len];
        
        // ファイルアップロード処理
        [[transferManager upload:uploadRequest] continueWithBlock:^id(AWSTask *task)
        {
            int errorCode = 0;
            std::string errorMessage = "";
            if(task.error.userInfo.count > 0)
            {
                // エラーハンドリングするのはここ
            }
            pDelegate->sendPhotoCallback(errorCode, errorMessage);
            return nil;
        }];
    }
}
```


これでs3へのファイルアップロードが出来ました。
一応ファイル名は被らないように日時+ランダム文字列で保存するようにしています。
次書くときはandroidの方を書いてみます。

vermudaではブログも書いています。よければのぞいてみてください。
http://engineer-blog.vermuda.jp/