iOS端末からYouTubeへ映像をアップロードするものを実装しました。


情報が少なく苦戦したので、メモを残しておきます。
参考にさせて頂いたサイト :
iPhone gdata-objectivec-client でYouTubeへ動画をアップ / 袖触れ合うも多少の縁
Google Data APIs Objective-C Client Library をXcode4で使う為の準備をした / エンジニアリングにはほど遠い

※GoogleとYouTubeアカウントそれぞれが必要になります。


1)まずGoogleDataAPIのgdata-objectivec-clientをダウンロードします。
Terminalから
svn checkout http://gdata-objectivec-client.googlecode.com/svn/trunk/ gdata-objectivec-client-read-only
をします。
・DLしたgdata-objectivec-clientのGData.xcodeprojファイルを
Finderから、自分のXcodeプロジェクトにドラッグ&ドロップでコピー
・コピーされたGData.xcodeprojを展開し、CommonフォルダとYouTubeフォルダをドラッグ&ドロップでGData.xcodeprojから外(自分のプロジェクト内)に移動します。(ここでGData.xcodeprojを自分のプロジェクト内からRemove Reference Onlyで削除)
・コピーしたフォルダの中身が黒色ならばコピー成功


2)Xcodeの自分のプロジェクト→TARGETS→Build Phases→Link Binary With Librariesの
+ボタンを押して以下のライブラリを追加します。

SystemConfiguration.framework
Security.framework
libxml2.dylib
※【ARC使用時】Xcodeの自分のプロジェクト→TARGETS→Build Phases→Compile Sources内の
追加されたファイルのCompiler Flagsに
-fno-objc-arc
を追加し、ARCを無効にします。
(現時点のライブラリはARC未対応なバージョンのため)


3)Xcodeの自分のプロジェクト→TARGETS→Build Settings内の編集
・Heder Search Pathsに

/usr/include/libxml2
を追加

・C Language Dialectに
C99 [-std=c99]
を選択

・Other C Flags/Debugに
-DDEBUG=1
を追加


4)ここで一度ビルドし、エラーが出なければ設定完了。


5)YouTubeAPIのDeveloper Key, Client ID, Client Secret IDの取得
参考サイト:YouTube API のデベロッパーキーを取得 / WEBエンジニアの技術調査ブログ
・上のサイトを参考にそれぞれ取得し、控えておく。


6)自分のXcodeプロジェクトに戻り、
ユーザーのアカウントログイン部分を実装します。
参考にしたサンプル:gtm-oath2
・ほぼサンプルの通りですが、以下のように実装しました。

- (void)signOut
{
if ([self.auth_.serviceProvider isEqual:kGTMOAuth2ServiceProviderGoogle]) {
// remove the token from Google's servers
[GTMOAuth2ViewControllerTouch revokeTokenForGoogleAuthentication:self.auth_];
}

// remove the stored google authentication from the keychain, if any
[GTMOAuth2ViewControllerTouch removeAuthFromKeychainForName:kKeychainItemName];

self.auth_ = nil;
}

- (void)signInToGoogle
{
[self signOut];

NSString *keychainItemName = nil;
if ([self shouldSaveInKeychain]) {
keychainItemName = kKeychainItemName;
}

NSString *scope = @"https://www.googleapis.com/auth/plus.me";
NSString *clientID = CLIENT_ID; // 先ほど取得したClient ID
NSString *clientSecret = CLIENT_SECRET; // 先ほど取得したClient Secret ID

if ([clientID length] == 0 || [clientSecret length] == 0) {
NSString *msg = @"The sample code requires a valid client ID and client secret to sign in.";
NSLog(@"%@", msg);
return;
}

SEL finishedSel = @selector(viewController:finishedWithAuth:error:);
GTMOAuth2ViewControllerTouch *viewController;
viewController = [GTMOAuth2ViewControllerTouch controllerWithScope:scope
clientID:clientID
clientSecret:clientSecret
keychainItemName:keychainItemName
delegate:self
finishedSelector:finishedSel];


NSDictionary *params = [NSDictionary dictionaryWithObject:@"en"
forKey:@"hl"];
viewController.signIn.additionalAuthorizationParameters = params;

NSString *html = @"
Loading sign-in page...
";
viewController.initialHTMLString = html;

[[self navigationController] pushViewController:viewController animated:YES];
}


[self signInToGoogle];のように呼び出せばWebView上にGoogleアカウントのログイン画面が現れます。
ログイン情報を入力すると、作成したAPI Accessの認証画面が開き、認証をするとログインが成功となります。


7)gdata-objectivec-client内のExample/YouTubeSampleを参考にアップロード部分の実装
・手順
1:アップロードする映像の準備
2:動画のタイトルや説明、カテゴリー、キーワードなどを設定
3:動画のタイプを指定し、それぞれを合わせる
2:GDataServieTicketでコールバックさせるよう設定をし、アップロード関数に投げる


- (void)uploadVideoFile
{
if ([self isSignedIn]) {

NSURL *url = [GDataServiceGoogleYouTube youTubeUploadURLForUserID:@"default"];

NSString *path = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"mov"];
NSData *data = [NSData dataWithContentsOfMappedFile:path];
NSString *fileName = [path lastPathComponent];NSLog(@"fileName : %@", fileName);

GDataMediaTitle *title = [GDataMediaTitle textConstructWithString:movieTitleStr];
GDataMediaCategory *category = [GDataMediaCategory mediaCategoryWithString:movieCategoryStr];
[category setScheme:kGDataSchemeYouTubeCategory];
NSArray *categoryArray = [[NSArray alloc] initWithObjects:category, nil];

GDataMediaDescription *description = [GDataMediaDescription textConstructWithString:movieDescriptionStr];
NSArray *keyArray = [[NSArray alloc] initWithObjects:movieKeywordStr, nil];
GDataMediaKeywords *keywords = [GDataMediaKeywords keywordsWithStrings:keyArray];

BOOL isPrivate = YES;


GDataServiceGoogleYouTube *service = [self youTubeService];

GDataYouTubeMediaGroup *mediaGroup = [GDataYouTubeMediaGroup mediaGroup];
[mediaGroup setMediaTitle:title];
[mediaGroup setMediaDescription:description];
[mediaGroup setMediaCategories:categoryArray];
[mediaGroup setMediaKeywords:keywords];
[mediaGroup setIsPrivate:isPrivate];

NSString *mimeType = [GDataUtilities MIMETypeForFileAtPath:path
defaultMIMEType:@"video/mov"];

GDataEntryYouTubeUpload *entry;
entry = [GDataEntryYouTubeUpload uploadEntryWithMediaGroup:mediaGroup
data:data
MIMEType:mimeType
slug:fileName];

SEL progressSel = @selector(ticket:hasDeliveredByteCount:ofTotalByteCount:);
[service setServiceUploadProgressSelector:progressSel];

GDataServiceTicket *ticket;
ticket = [service fetchEntryByInsertingEntry:entry
forFeedURL:url
delegate:self
didFinishSelector:@selector(uploadTicket:finishedWithEntry:error:)];

[self setUploadTicket:ticket];


GTMHTTPUploadFetcher *uploadFetcher = (GTMHTTPUploadFetcher *)[ticket objectFetcher];
[uploadFetcher setLocationChangeBlock:^(NSURL *url) {
[self setMUploadLocationURL:url];

}];
}
}


あとは、コールバックの関数でアップロードの成功/失敗を確認させます。


- (void)uploadTicket:(GDataServiceTicket *)ticket finishedWithEntry:(GDataEntryYouTubeVideo *)videoEntry error:(NSError *)error
{
NSLog(@"upload callbackkkk");
NSLog(@"userData : %@", videoEntry.userData);

if (error == nil) {

// 成功
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"アップロード成功"
message:[NSString stringWithFormat:@"%@ がアップロードされました", [[videoEntry title] stringValue]]
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
} else {
NSLog(@"エラー\n\n%@\n\n", [error description]);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"エラー"
message:[NSString stringWithFormat:@"エラー : %@", [error description]]
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
}
[mProgressView setProgress:0.0];
[self setUploadTicket:nil];
}


このような感じでアップロードが出来ました。

なかなか情報がなかったのと、YouTubeAPIについて調べが足らなかったのか
アップロードする映像のカテゴリーの内容を自由記述にしていたため
下記のようなエラーに長いこと悩まされました。。

Error Domain=com.google.HTTPStatus Code=400 "The operation couldn’t be completed.


結局はYouTube上にある正規なカテゴリー(AnimalsとかMusicとか)
を入れて解決する事ができました。