ラベル Salesforce mobile SDK の投稿を表示しています。 すべての投稿を表示
ラベル Salesforce mobile SDK の投稿を表示しています。 すべての投稿を表示

2013年7月9日火曜日

古いアプリをiOS6対応にしたらupside downにならない件を解決

■症状■

古いプロジェクトをiOS 6対応にしたら、portrait upside downにならない。NotificationでOrientationが変わったことは検出できるけど、Viewが回転しないので横向きになったまま。

iOS6のデフォルトではiPhoneではupside down以外が許可、iPadでは全方向が許可されていますので、それがそのまま効いていて変更できていない、ということになります。


■一般的な対策■

iOS 6ではshouldAutorotateToInterfaceOrientationが廃止になったので、対象ViewControllerでsupportedInterfaceOrientationsとshouldAutorotateを使う。


- (BOOL)shouldAutorotate {
    return YES;
}

-(NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskAll;
}

iOS 6対応として最初から作ったプロジェクトはこれで動きます。しかし、viewやらcontrollerをいろいろいじっている古くからのプロジェクトはこれではダメでした。

個人的困ったのはSalesforce対応アプリです。Salesforce mobile SDK for iOSの最新版ver 1.5でも未だにStoryboardやARCに対応していないので、中身は結構古いまま。テンプレートからiOS 6 targetにしても、upside downは働いてくれません。

その一方で…iOS 5をターゲットにすると、Web ViewのログインでID入力欄をタップしただけでSIGABRTするのは私だけでしょうか?


■原因■

root view controllerが別にあるためview controller上で上記shouldAutorotate / suportedInterfaceOrientationsをいじったとしても、標準のUINavigationController等で上書きされてしまう。


■解決策■

私のプロジェクトでは、Storyboard上のUINavigationControllerからメインviewを呼び出していましたので、UINavigationControllerのサブクラスNavigationControllerを作り、上記shouldAutorotate / supportedInterfaceOrientationsを貼ります。その上で、Storyboard上のnavigation controllerのcustom classをNavigationControllerに変更します。これでうまく行きました。いやはや。



■Salesforce mobile SDK for iOSの場合■

上記Salesforce mobile SDKの場合、テンプレートから作成されるプロジェクトはAppDelegate.hのnewRootViewControllerでViewとUINavigationControllerを生成しています。

上記と同じ手順でUINavigationControllerのサブクラスNavigationControllerを作り、AppDelegate.mにインクルードしてから、newRootViewControllerを書き換えます(書き換え箇所は赤字)。


- (UIViewController*)newRootViewController {
    RootViewController *rootVC = [[RootViewController alloc] initWithNibName:nil bundle:nil];
    NavigationController *navVC = [[NavigationController alloc] initWithRootViewController:rootVC];
    [rootVC release];
    
    return navVC;
}



2012年8月23日木曜日

Force.com SDK for iOS最新版

今週の月曜日から仕事でいじってました。

GitHubからzipで落としてもダメなのは以前と同じ。ちゃんとgitでcloneしてから./install.shしましょう。

今度のリリースでローカル・キャッシュなども加わったので、その辺もぜひ試してみたいんだけど、とりあえず会社の案件では用がないので保留…この週末にでも個人用アプリで試してみますべ。

で、新しいテンプレートですが…今度こそARCとかStoryboardに対応しているのでは?と3mmぐらい期待したのですが、してません。まぁARC無くても困らないんだけど、先週この案件に向けて下調べしていたViewはStoryboardが前提だったのでちょっと苦労しました。でも、まぁnibの方が素直というかイマイチ挙動を把握し切れていないSegueよりもわかりやすいので決定的な不利にはならないのですが。あと、今まで手動でやらなきゃいけなかった設定(Linkerのオプションとかライブラリの選択)が不要になっているのは少し楽。

今回の案件は「クラウド上のデータをiPad上に表示し、ユーザの操作を収集してクラウド上に上げる、てな案件のデモ版を作る」というものです。ViewControllerの数は5つ、Force.comは全部custom objectで6 objects、親子関係4世代とその横に親子関係2世代が参照関係でつながっているという単純なものです…と文字で説明しても「何のこっちゃ?」だと思いますが、一応勤務先の案件なのでご勘弁を。

ところで、このぐらいの規模のデモアプリ、他の人はどんな感じで作業しているんでしょうかね。

私の場合はざっとこんな感じ:

  • 月曜
    • SDKを新規インストールしてテンプレートプロジェクト作成
    • nibで要求仕様通りの画面構成を実装してNavigationBarなどが邪魔しないことを確認
    • Force.comで必要なデータベースを定義して一番基本的なデータがiOSアプリのUITableView上に表示されるところまで。ほぼ定時。
  • 火曜日
    • Tableからタップして表示されるUIPageViewControllerまわりの実装
    • ModelControllerとModelViewの役割分担がいまいちわかりにくくて試行錯誤
    • Force.comのデータを少し調整
    • ほぼ定時ぐらいで全データが表示されるようになり、全画面がとりあえず見られるような状態に
  • 水曜日
    • iPadからのpush側を実装。謎のデータ消失や重複が出たものの、ModelControllerをすっきり整理することで解消。正常操作と異常操作のマトリクスを作って動作をチェック、細かいところを直したり、ミリセカンド単位で収集しているはずのデータが秒単位だったのでForce.comの項目を18.0から15.3に変更したり。だいたい定時で動作確認も終わり

と、こんな感じでした。年寄りだから遅いのは勘弁してくださひ。

そういえば先月会社のお金でObjective-cの講習会に出たのですが、これが大変役に立ちました。特にメモリ関係で悩んだりハマったりすることが激減して、さくさく(当社比)書けるようになった…ような気がします。c言語とはなんだかんだで20年以上の付き合いになりますが、objective-cになっても変わっていねーなー、というのが正直なところ。

ああ、それでもやっぱりnilと[NSNull null]の混同で何カ所かハマりました。とほほ。

--

余談ですが、今日はFlexBuilderの作業。SuicaってかFeliCaをIDカードとして使ってForce.comに問い合わせをしたりメールを送ったり、という実装をしていました。

あー肩凝った、ってか疲れた。「あれ、ActionScriptって配列の要素の数はcountだっけlengthだっけ?」と悩んだりしているせいだとおもうんですけどねorz 明日はiPadアプリのアイコンなどを作ってお化粧する予定です。

まぁ何だかんだで、なかなか楽しい日々を送っております。はい。

2012年5月10日木曜日

Chatter APIにまつわる愚痴

会社で作業していると目的のAPIがなかなか出てこない。自宅で作業していると同じGoogle先生を使っているのに「FeedItem」でサクッとREST APIが出てくる。

何ででしょう? 昨日30分ぐらい「あれ、Chatterのメッセージにコメントがいくつついているかを返すメンバーって何だっけ? Comments?」ってGoogle先生をお供にさまよっていたんですが…今検索したら一発でFeedItemのCommentCountが出てきました。

見つかれば文句ないんですけどねぇ…。

それにしても個人で提出したiPhoneアプリ。今までの経験から「審査待ちまですくなくとも1週間」ってのはわかっているんですが、それにしても待ち遠しい。

2012年5月6日日曜日

Native iOSアプリをChatterの「いいね!」に対応

■FourChatter絶賛改良中■

Chatter上の文言をサクっと検索する倉橋屋謹製アプリFourChatterを改良してます。今更ですが。主な改良のポイントは以下の2点:
  1. iPad対応
  2. 「いいね!」の実装
iPad対応は、同じGUIそのままならそんなに苦労はないけれど、このFourChatterは「iPhoneの向きを変えるだけでキーワードを切り替えて検索できる」ってのがウリです(電車の中ではちょっと恥ずかしいけどね)。が。iPadで向きを変えるのは結構ウザい。というよりも、五十肩の私にはしんどい。というわけで、Segmented Controlを導入しました。

…iPhone版もこれでいいんじゃね? Segmented Controlなら4つに限らなくても良いんじゃない??という声もありますが。


■「いいね!」の実装■

Chatterの「いいね!」はFeedLikeというオブジェクトを使ってます。NewsFeedまたはFeedCommentへのto one relationshipになっていて

  • CreatedByID - 「いいね!」をクリックしたユーザのID
  • FeedItemID - 「いいね!」の対象となるNews Feed ID
  • FeedEntityID - 「いいね!」の対象となるFeedまたはCommentのID
  • InsertedById - このオブジェクトを作ったユーザのID
もともとFeedEntityIDはなかったと思うけど、最近FeedCommentへの「いいね!」がサポートされたことにともなって追加された、ような気がします。


■まず「いいね!」はこんな感じ■

SFRestRequest *requestInsert;

NSString *fId = [feed objectForKey:@"Id"];

NSDictionary* dic = [NSDictionary 
    dictionaryWithObjectsAndKeys:fId, @"FeedItemId", nil];

requestInsert = [[SFRestAPI sharedInstance] 
    requestForCreateWithObjectType:@"FeedLike" fields:dic];
[[SFRestAPI sharedInstance] send:requestInsert delegate:self];

これでOK。実行結果は例によって以下が呼び出されます。

- (void)request:(SFRestRequest *)request didLoadResponse:(id)jsonResponse ;
- (void)request:(SFRestRequest*)request didFailLoadWithError:(NSError*)error ;
- (void)requestDidCancelLoad:(SFRestRequest *)request ;
- (void)requestDidTimeout:(SFRestRequest *)request ;

要するに「いいね!」をしたいfeedのidを"FeedItemId"にセットしたNSDictionaryを用意して、それをFeedLikeとしてinsertするだけです。


■いいね!を取り消すには■

上記で作ったFeedLikeを削除します。最初、SELECTで該当するFeedItemIDとCreatedByIDを持つFeedLikeを検索しようとしたのですが、FeedLikeは直接fetchできないというエラーが出ました。ので、NewsFeedをfetchする時に、一緒にFeedLikesもfetchしておきます。

NSString *strQuery = [NSString stringWithFormat:
     @"SELECT Id, (SELECT Id, CreatedById From FeedLikes) 
       From NewsFeed Where Id = '%@' Limit 1", fId];

で、FeedLikesの中から自分のUser IDと同じCreatedByIdを持つFeedLikeを探し出して消します。

fId = (NSString *)[feedLike objectForKey:@"Id"];
requestDeleteLike = [[SFRestAPI sharedInstance] 
    requestForDeleteWithObjectType:@"FeedLike" objectId:fId];
[[SFRestAPI sharedInstance] send:requestDeleteLike delegate:self];

とても簡単。なお、自分以外のユーザの「いいね!」を消せるかどうかは試してません。

2012年5月5日土曜日

Force.com SDK iOS - ログインUser IDの取得

小ネタですが。

Force.com mobile SDK for iOS Nativeアプリで、ログインしているユーザのIDを取得するには、

AppDelegate *app = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSString *userId = [[[app coordinator] credentials] userId];

てな感じで。SFOAuthCoordinatorSFOAuthCredentialsは、他にも使えるメンバーを持っているのでリファレンスをブックマークしておくと良です。

で。上記で取得したのは15文字のuser idなので、18文字のCreatedByIDと比較する場合は

if ([createdById hasPrefix:userId]) { ... }

と書かないとダメです。

--

余談ですが。

考え事をしながら引き出しから爪切りを取り出し、床に広げた新聞紙に座り込んでさて爪を切ろうかと思ったらUSBメモリだった。そんな経験をした人はこの世の中に何人ぐらいいらっしゃるのでしょうか。
色とサイズは似ているけど…

2012年1月18日水曜日

Salesforce mobile SDK for iOS +1

■テンプレート以外で作業する場合のTips 1■

SFAuthorizingViewControllerにこんなのが定義されてますが。

    @property (nonatomic, retain) IBOutlet UIView *oauthView;  

これ、使われていません。テンプレートについてる「Authorizing」の画面があまりにもスゴいので当然置き換えを考えるわけですが、置き換えたxibでちょっと小細工をしたものの、どうも思ったとおりの動作をしてくれない。何だかんだ調べたら、oauthViewは全然使われていませんでした。

普通にviewをFile's Ownerにしてください。

2011年12月31日土曜日

Salesforce mobile SDK正式版(GA)

■βが取れました■

まぁとりあえず、めでたいです。今後はドキュメントなども充実してくれますよーに。



■では試してみましょう■

というわけで、例によってGitHubから最新版を落としてきます。もしXcodeが立ち上がっていたら、念のため終了しといてください。なお、私の環境ではGitHub for Macでの同期がうまく働きませんでした。ので、zipを落としてきます。

SalesforceMobileSDK-iOS

落としたら、zipを解凍したディレクトリに移り、 ./install.shを実行します。例によって数分後、BUILD SUCCESSFULが出たら無事終了です。

さて、Xcode 4.2を起動します。New Projectを選ぶと、以前よりちょっと派手なテンプレートアイコン「Hyblid Force.com App」と「Native Force.com REST App」が追加されています。今回はサクっと Native を選びます。


次の「Choose options for your new project」でProduct Nameに適当なプロジェクト名、iTunes connectなどに登録したあなたの会社ID、Consumer KeyにはあなたのSalesforce/Database.com組織のリモートアクセスキー、Redirect URLにはその戻り先URLを入力します。

Xcode 4.2だとその下の「Use Automatic Reference Counting」をonにしたいのですが、残念ながらMobile SDKが対応していないのでここはチェックを外してください。外さないとビルドエラーの塊になります。すべて入力したらNextをクリックし、プロジェクト保存先を指定し、プロジェクトを作ります。

以前はここでOther linker flagを設定したりFrameworkを追加する一手間が必要だったのですが、さすがはβでないGA、さくっとそのままcmd+Rで実行できます。起動すると、黄土色の「Authorizing」画面が表示され、その後Salesforce.comのOAuth認証画面になります。ID, Passなどを入力すると、その組織のユーザが10名分表示されます。


■βとの差異■

βはAppDelegateに認証関連の処理を細々と書かなければいけませんでしたし、「認証中です」の画面も自分でイチから作ってやらなければいけませんでした。でも、1.0では、その辺の処理はSFAuthorizingViewControllerとSFNativeRestAppDelegateに実装されていて、AppDelegateにはごく僅かなコードを書くだけで処理してもらえます。本来のAppDelegateに書きたい処理と分離することができて、非常にすっきりしました。

ViewControllerに関しては元々テンプレートが作ってくれるコードは非常に単純なので、あんまりRESTがどうこう考えないで実装することができます。


■そして、ハマる(お約束)■

以下は余談です。

とりあえず、プロジェクトの構造などを検証するために今度はMobile SDKのテンプレートを使わずにアプリを作ってみることにしました。
  1. Single View Appテンプレートでプロジェクトを作る
  2. さっきNative Force.com REST Appで作ったプロジェクトからDependenciesフォルダとNativeRestAppフォルダをコピー
  3. 必要なFrameworkを追加
  4. AppDelegateとViewControllerに必要なコードをコピペ
  5. cmd+Rでビルド&RUN
アプリは無事シミュレータ上で起動し、ドドメ色の「Authorizing」から認証を得て…オチますorz

これが3日ほど前でした。それから他の作業もしつつ、いろいろ原因究明したんですが、どうやっても同じところで落ちます。以前のパターンで同じようなエラーが出た時にはdelegateのスペルが間違っていたのが原因だったので、今回も何かdelegateを抜かしているのではないかと思い、ソースをにらめっこする日々でした。でも治らない。

その辺のウダウダを書いてもしょうがないので、例によって最終的に解決に至った課程のみ書きます。
  • エラーが出ているのは、viewDidLoadの下記の行
[[SFRestAPI sharedInstance] send:request delegate:self];
  • SIGABRTで止まった時点でのスタックトレースを見る←最初にやっとけ
  • [SFRestRequest description」でググる→SFRestRequest.mのソースがヒット
SFRestRequest.m
  • ソースに以下の記述を発見
  • _queryParamsはNSDictionaryなので当然JSONRepresentationなどというメソッドはない。遅まきながら、ここで「カテゴリ」が実装されてないことに気づく

原因は…上にヒントが書いてあります。

Other Linker Flagsに-ObjC -all_loadがセットされてない

でした。お粗末さまでした…。

言い訳をするとね…以前これらのLinker Flagsがセットされていない時にはビルドエラーで止まったのよ…。

2011年11月13日日曜日

PhoneGap 1.2.0 + Salesforce SDK(hyblid)


■Salesforce mobile SDK 2011-11版■

ちょっと試してみたいことがあって久しぶりにSalesforce mobile SDK for iOS / hyblidを使ってみようと思ったら、11月の頭にSalesforce mobile SDKのアップデータが出ていました(リビジョン番号とかないのかしら)

そのまま放置していたらPhoneGapからは1.2.0が出てました。ついでなので、先にこっちをアップデートします。


■PhoneGap 1.2.0■

それにしてもOpenSourceはバージョン進むの速いな。おっさんは着いていくだけで精一杯だわ。というわけで、1.2.0を落とします。Xcodeは終了しておくこと。

iOSフォルダの中を見ると例によってdmgパッケージになっているのでダブルクリックしてマウント、Uninstall PhoneGap.appで古いヤツを消してから、インストーラを起動します。

#uninstallするのは必須ではないですが、まぁ古いMacOSユーザの習性です#

インストールはサクサク進む、はず。あとは例によって
  • Xcodeを起動
  • PhoneGap-Based Applicationをテンプレートとして新プロジェクトを作る
  • できたプロジェクトをFinderで開いて中のwwwフォルダをXcodeの新プロジェクト上にDrag & Dropして"create folder reference"で追加
  • PhoneGap.plistのExternal hostsに*を追加
  • ビルド
ってことで、無事デモアプリが起動します。「あれkitchen sinkはどこだっけ…?」と思ってしまった自分が悔しい。それはTitanium mobileやがな。PhoneGapでもああいうの欲しいなぁ。


■あらためてSalesforce mobile SDK、の前に■

SDKはgithubに公開されていますので、メンテナンス情報などを取得する意味でもgithubアカウントがあると便利です。というか無いと不便すぎてストレス溜まります。無料なので、取ってしまいましょう。かくいう私もつい先日作ったのですが、便利すぎて今までの苦労があほらしくなりました。githubアカウントを使うには公開鍵が必要ですので、もしまだ作っていなければ、作ります。
で、ここから無料のアカウントを作ります。特に難しいこともないので、省略しますが、さっき作った公開鍵はgithubにログインしてAccount Settings>SSH Public Keysに登録します。あなたのマシンとgithubはsshで通信するので、そのための暗号キーを設定するわけですね。なお、ものすごく蛇足ですが、秘密キーは絶対公開したりヒトに見せたりしてはいけません。

さて、次。Macからgithubを扱うのであれば、GitHub for Macがあると圧倒的に便利ですので、これも入れます。インストールしてセットアップを終えると、あら不思議、githubのsalesforce SDKのページにさっきまで無かった「Clone in Mac」のアイコンが出てきます。クリックするとGitHub for Macがダウンロードを開始します。便利すぎて笑えます。

次に、もしまだgit入れてない人は、入れましょう。サブモジュールなどをgitから取ってくる形式になったので、gitないとうまく使えません。そしてgitを入れるにはMacPortってのがあると簡単です。MacPortをインストールして、それからgitをインストールし、そこからSalesforce mobile SDK 2011年11月版を入れましょう。




■今度こそSDK…のビルド■

…いやー、準備が長かったw というわけで、GitHub for Macのおかげで安全かつ迅速に、SalesforceMobileSDK-iOSが用意できました。ターミナル.appを起動して、SDKをインストールします。とりあえず私は安易にDesktopに置きましたが、そうでない方は水色の部分を変えてください。
cd
cd Desktop/SalesforceMobileSDK-iOS
./install.sh
だーっと滝のように文字が流れます。マシンの性能によって違いますが、数分間続きます。最後に:
all:

BUILD SUCCESSFUL
Total time: 10 seconds
と表示されればOKです(secondsは変わると思いますが)。お疲れ様でした。


■ようやくサンプル(今度こそ)■

SalesforceMobileSDK-iOS/hyblid/SampleApps/ContactExplorerの中にあるContactExplorer.xcodeprojをダブルクリックするとXcodeが起動します。

さくっとビルドすると警告が出てしまいます。そうです、Consumer Keyなどが未登録ですね。というわけで、AppDelegate.hを開き、RemoteAccessConsumerKey, OAuthRedirectURI, OAuthLoginDomainを登録します。
  • RemoteAccessConsumerKey
ここに説明が書いてありますが詳細すぎてわかりにくいですね。Salesforceにログインして 設定>アプリケーションの設定>リモートアクセス>新規 で適当なアプリケーション名、コールバックURL(後述)、連絡先メールアドレスを登録してください。コンシューマ鍵として長い記号のような文字列が表示されますので、それを設定します。
  • OAuthRedirectURI
上記コールバックURLと同じものです。OAuthの認証には暗唱方式とコールバックURL方式があって…と説明すると長いですが、mobileアプリの場合には https://login.salesforce.com/services/oauth2/success を設定します。これでないと、認証を中断した時などに二度とログイン画面が出てこなくなります(経験者は語る)。
  • OAuthLoginDomain
これはSalesforceにログインする時にお馴染みの login.salesforce.com をセットします。デフォルトではサンドボックスに接続するために test.salesforce.com になっていますが、サンドボックスを使う場合と本環境とではここで切り替わるようになっているようです。ただし、本番とサンドボックスを切り替える場合には、上記コンシューマ鍵もそれぞれの環境で作った別のものが必要ですのでご注意ください。
これでようやくcmd+Rできます。長かった…orz

ビルドが終わるとエミュレータが起動し、スプラッシュ画面の後、Salesforceのログイン画面になります。ここであなたのSalesforce idとpasswordを入力します。ログインに成功すると、このアプリからSalesforceへのアクセスを許可するかどうか確認する画面になります。認証すれば、このページの冒頭に貼ったような画面に切り替わるはずです。

お疲れ様でした。

いやー、読むのも大変だったと思いますが、いろいろググって正しい記述かどうかを確認しながらこれを書いたので、休憩を除いて4時間ぐらいかかりっきりでした。

…冒頭、「調べたいことがあったので」と書きましたが…今日はもういいや。忘れないようにモニタにポストイットを貼って(アナログだな)、また後日。

お疲れ様でした(大事なことなので(ry