カテゴリ: Objective-C
投稿者: yoshigiwa
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とか)
を入れて解決する事ができました。
カテゴリ: Xcode
投稿者: mio
2台目以降のMacで実機テストできるように証明書などの設定をしていて、表題のエラーが出てきてハマってしまったので、その解決方法を書いておきます。

ちなみに、オーガナイザーで出たエラーはこんなものでした。
xcode could not find a valid private key / certificate pair for this profile in your keychain.
プロビジョニングファイルのStatusに Valid signing identity not found

エラー画面


1台目の認証の仕方は、いろんなサイトで紹介されていますが、2台目のことはあまり書かれていない。

結論を先に書くと、1つのApple IDで、2台目以降のパソコンで Xcodeの実機確認のための認証をするためには、1台目で作った証明書を使う必要がある(っぽい)ので、1台目のMacの証明書を書き出して、それを2台目にインストールする必要があるのです。

そのため、多くのサイトで紹介されているような、「キーチェーンアクセス」>「証明書アシスタント」>「認証局に証明書を要求」から証明書要求を書き出す作業や、その証明書要求ファイルをADCにアップロードする作業は必要ありません。(1台目で証明書は既に作成しているため)

このステップの代わりに必要なのは、1台目のキーチェーンアクセスに入っている証明書要求の秘密鍵(Apple IDの「名 姓」というファイル名のもの)を書き出して、書き出したファイルを2台目にインストールする作業です。


以下では、書き出す作業の流れを説明しています。

1)
1台目のMacでキーチェーンアクセスを立ち上げ、左の「分類」ペインから「鍵」を選択、証明書要求の秘密鍵のファイル(選択すると、秘密鍵,RSA,2048-bitなどと出る)を右クリックして、"(Apple IDの「名 姓」)"を書き出すというメニューを選択します。

画面1


2)
フォーマットは、「個人情報交換(.p12)」を選択、ファイル名は何でもOK。「保存」を押します。

画面2


パスワードの設定を求められますが、何も入力しなくてもOKです。セキュリティ的に何か設定しておいた方が良いと思いますが、面倒な人は何も入力しないというのでいいと思います。「OK」ボタンを押すと、「.p12」のファイルが書き出されます。




3)
書き出した .p12 ファイルを、2台目のMacに送って、ダブルクリックをすれば、無事秘密鍵の複製が完了です。おそらくこの作業が終われば、上記のようなエラーは発生しなくなるかと思います。

4


残りの、プロビジョニングファイルのインストールや、iPhone実機の登録方法などは、1台目のときと変わりません。

これは私の仮説ですが、2台目以降の認証要求の鍵に1台目のものを使う必要があるのは、秘密鍵を生成するときに、ランダムに生成された鍵を利用しており、仮に2台目で新しい認証要求の鍵を作ったとしても、ADCに登録されている証明書に埋め込まれている1台目で生成した鍵と一致しないためだからかもしれません。

解決に1日ぐらいかかったので、他の人のお役に立てれば嬉しいです。


stack overflow のサイトで、似たようなエントリーがあり、
The error "XCode could not find a valid private-key/certificate pair for this profile in your keychain." means you don't have the private key.
Maybe because your Mac was reinstalled, maybe because this key was generated on another Mac. So to be able to use your certificates, you need to find this key and install it on the keychain.
などと書いてあったので、そういうことかなと思いました。

カテゴリ: General
投稿者: mio
XCodeで、デバッグ中のアプリを、ホームボタン2回押しで、アプリの左上にある「-」ボタンを押して終了した後、もう一度起動しようとすると、

mainの関数の
int retVal = UIApplicationMain(argc, argv, nil, nil);
という行に
Thread 1: program received signal "SIGKILL"
と出ます。

sc1


すると、ホームボタンを押しても、画面が真っ暗なままになってしまい、操作がほとんど効かない状態になってしまいます。シミュレーターでも実機でも、同じ症状になり、復帰するには、実機の場合は電源ボタンを一度押してロック解除して元の画面に戻るか、シミュレーターの場合は、シミュレーターを終了して立ち上げ直したりする必要があります。

いろいろ試して分かったのですが、この症状は、XCodeでRunして、デバッグ中のときだけ発生するようでした。そのため、XCodeで、Stopさえしてあれば、このようなことは起こらないと分かりました。


最初、アプリを終了するときに必要な処理が十分に行われていないことが原因で、この問題が発生しているのかと思って、かなり悩んでいたのですが、簡単なことでホッとしました。
カテゴリ: Xcode
投稿者: terada
XcodeのOrganizer>LIBRARY>Developer Profileで確認できる開発者プロファイル情報は、Import/Exportに対応しているのですが、なぜかXcode4.0ではインポートが正常にできませんでした(パスフレーズが間違っています的なアラートが出る)。Xcode4.0でエクスポートしたファイルをXcode3.xでインポートすることは出来たのですが・・・。もう一度、Xcodeを再インストールしてやると正常にインポートできました(アンインストールの必要はなし)。
カテゴリ: General
投稿者: yoshigiwa
制作したアプリをApp StoreでリリースするにはiTunes Connectでアプリの審査を通過する必要があります。
この手続きも一筋縄ではいかないものだったりします。
今回は無料アプリの申請をしてみたのでメモしておきます。
有料の場合は登録の際に税金の手続きやいろいろとまた更に時間がかかりそうです。

制作したアプリをiTunes Connectで申請する手順は
? : iTunes ConnectでLoginし、Manage Your Appをクリック
null
 ここでアプリの情報やスクリーンショットなどを登録します。
 (ここはさほど難しくないので割愛します。)
 各項目の記入を終えて、アプリがupload待ちの状態になった事を確認したら、Xcodeでアプリをビルドするための準備をします。

? : iOS Provisioning Portalにいきます。
 前回ここで実機テストをする際に、実機テスト用の認証キーを作成してキーチェインに登録する必要がありました。
 今度は、配布用の認証キーを新たに作る必要があります。

? : Certificates > Distribution で前回と同じように認証キーを作成 > ダウンロード > キーチェイン登録

? : Provisioning > Distribution で同じように認証キーを作成 > ダウンロード > プロビジョニングを~/Library/MobileDevice/Provisioning Profilesにコピー

? : Xcodeを起動し、左側の"グループとファイル"のプロジェクトファイルを右クリック >"情報を見る">"構成"タブへいきます。
 ここで、"Release"を選択し下の"複製"ボタンをクリックして複製されたものの名称を変更します。(任意な名前)
 名前を変えたら下の"ビルドが使用するコマンドライン"をいま作成したリストに切り替えます。

? : "ビルド"タブを選択し、"構成"を上で作ったものを選択
 すぐ下の設定の"コード署名"の"コード署名ID"内の"Any iOS Device"の右側を上の?で作った"Distribution"を選択

? : 同じようにターゲットファイルも"情報を見る"から"ビルド"タブで"構成"を変更
 下の"設定">"コード署名">"コード署名ID">"Any iOS Device"の右側の"Distribution"を変更

? : Xcodeの上のツールバーから"プロジェクト">"アクティブターゲット""を編集"を開き、上記二つと同じように"ビルド"の"構成"を変更し、同じように下の"Distribution"も変更

? : "グループとファイル"の"info.plist"を選択し各種項目を入力
 ここはXcodeのプロパティリストエディタが参考になります。
 Iconの設定はCFBundleIconFilesでiPhone3G(57*57)/iPhone4(114*114)/iPad(72*72)のアイコンをまとめて記入しないとエラーが出るので注意。

? : Xcodeの左上の概要で"Device"を選択し、"構成"を?で作ったものを選択

? : 上のツールバーから"ビルド">"Build and Archive"
 ビルドに成功したらオーガナイザが開きます。

? : 開いたオーガナイザで左側の"IOS DEVELOPMENT"内の"Archived Applications"を選択すると、右側に先ほどビルドしたアプリが出てきます。その下にビルドした時間が表示されるのでそれを選択

? : 下の"Submit Application to iTunes Connect..."をクリックしてビルドしたアプリをiTunes Connectにuploadします。

? : これで成功したらUpload完了、iTunes Connectのサイトで申請したアプリがWaiting for Reviewになる筈です。


?の部分で何度も同じ"Application failed codesign verification."というエラーが出て2〜3時間戦いました。。
結構誰もが通る関門のようで、やり方を解説してるサイトが沢山ありました。
その中で今回、特に参考になったサイトは下のサイトです。

iPhone/申請方法 - MinacoWiki
Application Loaderでファイルをアップロードするところで詰まってます。助けてください。 « 寺子屋サルでき
アプリ申請エラーの解決法「Application failed codesign verification. 」

その他にも解説しているサイトは沢山ありますので、調べると結構出てきます。

2010/11/08: iPhone実機テスト

カテゴリ: General
投稿者: yoshigiwa
この回からMobile Devを引き続き更新していこうと思います。

iPhoneアプリ開発で実機テストをするためにはiPhoneDeveloperProgramで認証登録する必要があります。

登録情報記入 > FAX確認 > iOS Developer Program購入 > アクティベートという長い道のりを経ての実機テストを登録する作業に入ります。
一つだけ特につまづいてしまった点は、Current Development Certificatesの登録の際に必要になる.cer拡張子の証明書アップロードの.cer拡張子の作成でした。

アプリケーション > ユーティリティ > キーチェーンアクセス のツールバーから
キーチェーンアクセス > 証明書アシスタント > 認証局に証明書を要求... で作成できてるの筈なのにアップロードがうまくいきませんでした。

エラー内容

ファイル拡張子が違うみたいな事が書かれてます。
どの参考サイトにも載っておらず少し混乱しましたが、ここは作成した証明書CertificateSigningRequest.certSigningRequestをCertificateSigningRequest.cer
に拡張子を短くするだけで無事アップロードできました。

ここからはサクサクとDevices登録、AppIDs登録、Provisioningを完了させて念願のiPhone実機テストに辿り着く事ができました。
既に多くのページで細かい手順を説明されているのですが、今回はumelog.comさんのページを特に参考にさせて頂きました。
カテゴリ: General
投稿者: mio
C言語の子孫みたいなのはたくさんあるようですが、違いというか誕生した順番や、おおよその違いを知りたかったのでエントリーを作りました。

C : 1971年誕生。前身はB。
C++ : 1983年誕生。オブジェクト指向になった
C# : 2001年誕生。マイクロソフトが作った。ECMA準拠。
Objectvie C : 1983年誕生。NextSTEPなどを経て、Appleが開発した。最新はver. 2.0

C# は、windowsでしか動かない
Objective C は、MacやiPhoneでしか動かない

C, C++ は割とニュートラルな存在っぽいです。
カテゴリ: Objective-C
投稿者: mio
Xcodeのメニューから、
Xcode > 実行 > コンソール
をクリックすると、
デバッガコンソールが立ち上がり、
そこでログが確認できるようになる。

デバッガコンソールのショートカットは、
Command + Shift + R

プログラム内では、以下のように書く。
NSLog(@"Hello world!");
int型の変数などは、型変換しないといけないようです。

デバッガコンソール


どうやって iPhone で trace 文書くの??
カテゴリ: General
投稿者: mio
iPhone開発本を読み始めて、最初になんだコリャ?と思った、クラス名にやたらとついてる「NS」という表記が何なのかやっと分かりました。

MacOSの前身であるNEXTSTEPというOSが1987年〜1996年ぐらいまであったらしいのですが、それがObjective-Cで書かれていたらしく、NEXTSTEPを略して、NSとし、それを、クラスライブラリのトップにあるObjectクラスの頭に付けちゃったということらしい。

最初NSという表記を見たとき名前が特殊な感じがして、iPhoneに特有のクラスかと思いましたが、どうやらObjective-C全体がそうなってるようですね。

ちなみに、クラス名の接頭辞で、NS以外にも、UIやCAなど、いちいち接頭辞が付いているようですが、それは、Objectctive-Cが言語使用として、クラススコープを備えていないからで、間違って最初からあるクラスと同じ名前をつけてしまわないように、という理由があるとかないとか、そんな感じみたいです。

2009/08/05: About

カテゴリ: About
投稿者: mio
iPhoneアプリ開発のTips集です。
既に、巷にiPhone Tipsは溢れていますが、
つまずいた点などをまとめていければと思います。

Objective C は未踏領域でしたが、
基本Flasher視点で、
足を踏み入れてみようと思います。

trace("Hello iPhone !");
NSLog(@"Hello Flash !");

といった感じで。


2009.8.6. 現在の参考図書
・ユメみるiPhone
・iPhone SDK プログラミング大全
・iPhone SDKの教科書
・詳解 Objective-C 2.0

2009.8.6. 開発環境
・iPhone 3G (3GSではない方)
・MacBookPro 13inch OSX 10.5