どうも私です。小林です。アプリ担当だけどなんやかんや経理とか採用とかもやってます。

皆さん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:UIImagePickerControllerSourceTypeSavedPhotosAlbum])
    {
        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:)])
    {
        // sendPhotoを呼び出す
        [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の方を書いてみます。

お見積いたします。どんなことでも、お気軽にご相談ください。

お客様のご要望とご予算に応じて最適なソリューションをご提案いたします。
VRの開発やアプリ開発以外でも、ぜひ一度ご相談ください。