2012年11月23日金曜日

今日はムービーアプリ

■例によってハマり方面■

お友達からの依頼で、ムービー再生系のiPhoneアプリを作ってます。ムービーアプリなんてSymantec C++以来かもしれない。あまりにも久しぶりなんで、どのFrameworkが最新だかわからないレベルです。MediaPlayer.frameworkですが。

簡単なアプリですがハマったのは以下2点。まぁね…ハマる以前だけどね。

画面真っ黒になるだけで何もでない
▶MPMoviePlayerViewControllerではなくMPMoviePlayerControllerを使っていた。

参考にしたサンプル・コードにはMPMoviePlayerViewControllerって書いてあったのですが、Xcodeの入力予測を使った時に間違ったようです。MPMoviePlayerViewControllerに変えたらムービーのコントローラなどがちゃんと表示されました。でも、ムービー表示領域は真っ黒で「Loading...」が表示されたままです。

Loadingのままで先に進まないし、play直後にfinishしてしまう
▶fileURLWithPathではなくURLWithStringを使っていたorz

困ったときのStackOverFlowさんありがとう。

Storyboard + ARCで作っているけど、Objective-C 2.0をちゃんと勉強した後となっては正直ARCにあんまりメリット感じません。Javaとは言わないけど、せめてC++的にスタックで自動的にお掃除してくれるなら文句ないんですが。

このところ会社ではずっとTitanium mobileをいじってます。JavaScriptなんでメモリの後始末を考えなくて良いという点「だけ」は良いものの、やっぱりネイティブの方が楽です。APIなどが確実に動く(Titaniumはbound関係のAPIで値が返って来なかったりすることが多い)し、何よりInterfaceBuilderが使える。Titaniumだと「画面上に配置したオブジェクトを全部50dp下げる」なんてことが起こると座標をいじらないといけないので面倒くさくていけません。

2012年10月28日日曜日

Force.com SDK for iOSをStoryboard対応に

Force.com SDK for iOSのテンプレートを簡単にStoryboard対応にする方法をまとめました。以前はRestKitがソースごと提供されていたのでスプラッシュも含めて変更可能だったのですが、今はバイナリとヘッダだけになってしまったので簡単にはいじれません。

そこで、SFAuthorizingViewController.xibはそのまま残して、それ以外をStoryboard対象とします。

1.新しいプロジェクトをテンプレートNative Force.com REST Appから作る

Use Automatic Reference Counting(ARC)チェックはオフで。

2.新しいStoryboardを用意してTableViewControllerを貼る。

Storyboardの名前はStoryboardとします。新しく出来たStoryboardは何も入っていない状態なので、ここにTable View Controllerを貼ります。

3.Table View Controllerの設定

カスタムクラスとしてRootViewControllerを設定し、View ControllerのIdentifierを rootView にします。Storyboard上のPrototype Cells下にあるTable View Cellをクリックし、Identifierを CellIdentifier に変更します。

4.ソースの変更

AppDelegate.mのを以下のものと差し替えます。


- (UIViewController*)newRootViewController {
    UIStoryboard *storyboard 
        = [UIStoryboard storyboardWithName:@"Storyboard" 
                                    bundle:[NSBundle mainBundle]];
    RootViewController *rootVC 
        = [storyboard instantiateViewControllerWithIdentifier:@"rootView"];
    
    UINavigationController *navVC
        = [[UINavigationController alloc] initWithRootViewController:rootVC];
    
    return navVC;
}


5.SFNativeRootViewController.nib削除


残してあっても影響ないので、削除しなくても変わりありませんが。


以上で、OK。iPhone Simulatorを選んでRunするとちゃんとAuthorize画面が出て、認証後Table Viewに進みます。あとはよろしく:-)

2012年10月23日火曜日

iOS開発環境の移行

■証明書.p12を保存しておこう■

旧マシンからの移行はiTunes Connectなどのおかげもあって割と簡単なのですが、重要なことが一つ。

iTunes Connectに公開鍵などを登録しますが、その時に使った証明書.p12を保存しておかないと新しい環境上でプロビジョニングなどを有効にすることができません。

新しいマシンのXcode / Organizer上でプロビジョニング行の一番左に黄色い三角と「valid signing identify not found」の文字が表示されて実機テストが出来なくなってしまいます。

もし保存していなかった場合には、旧マシン上でKeyChainから証明書をダウンロードする必要があります(もし旧マシンが死んじゃった場合にはどーすんだろ…プロビジョニングなどを全部消してやりなおしたという記事は見たことありますけども…)
  1. アプリケーション->ユーティリティ下にあるKeyChainを起動して左下にある「鍵」をクリックします。
  2. 右側に表示される一覧の中から、iTunes Connectへの登録時に使ったApple ID名の秘密鍵を右クリック、「"名前"の証明書を書き出す」を選びパスワードを登録します。
  3. ファイルを適当な場所に保存し、新しいマシンに移し替えます。
  4. 新しいマシンで証明書.p12ファイルをダブルクリックするとKeyChainが起動、パスワードを入力します。
これで証明書が確認されます。Xcode / Organizer上のプロビジョニングがちゃんと有効になっている、はずです。

2012年10月22日月曜日

Titanium studioのLionへのインストール

真っさらのLionにTitanium studio 2.1.2をインストールして起動したら、Permission Deniedエラーが出ました。/Library/Application SupportにTitanium SDKをインストールできない由。

ググると「Library/Application Supportのパーミッション変えろよwww」って悪魔のような回答が英語で山ほど出てくるのですが、それはさすがにセキュリティ的にいけません。

本当は~/Library/Application Support/下にTitanium SDKをインストールするのがLion的な流儀だと思うのですが、Titanium StudioのPreference->Aptana->TitaniumでTitanium SDK Homeを変更しようとしても変更できません。

ということで、妥協Work Aroundですが…自分で/Library/Application Support/Titanium/を作ってやればOKです。

1.Titanium Studioを終了


2.Finderで/Library/Application Supportへ移動

Finderで「ライブラリ」が見えない時には、Finderを選んだ状態でoptionキーを押しながら移動メニューをクリックします。で、見えたら直下のApplication Supportをクリック


3.新しいフォルダを作る

ここに新しいフォルダを作ると管理者パスワードを聞いてきますので、認証します。


4.フォルダの名前を変更する

名称未設定フォルダの名前を Titanium に変更します。この状態では自分自身がTitaniumフォルダのオーナーなので起動したアプリからここに書き込みができます。

これでTitanium Studioを起動すれば、workspaceの設定、Appceleratorアカウントの認証などの後、Titanium SDKが自動的にダウンロードされ、使えるようになるはずです。

いやはや。なお「今更Lionかよ」…という突っ込みはナシの方向で。

2012年10月21日日曜日

Force.com IDE on Eclipse juno

まっさらなMacOS X Lion環境にEclipse junoをインストールし、Install New SoftwareからForce.com IDEを入れようとしたら以下のエラーが出て失敗しました。


Cannot complete the install because one or more required items could not be found.
  Software being installed: Force.com IDE 25.0.0.201206181021 (com.salesforce.ide.feature.feature.group 25.0.0.201206181021)
  Missing requirement: Force.com IDE 25.0.0.201206181021 (com.salesforce.ide.feature.feature.group 25.0.0.201206181021) requires 'org.eclipse.update.ui 0.0.0' but it could not be found


調べたところ、このWork aroundで無事解決しました。

1.HelpメニューからEclipse Market Placeを選択

2.Find:に "EMF Compare"と入力してGO

3.検索結果から "EMF Compare : model comparison and merge"のInstallボタンをクリック

4."EMF Compare ..."を選択し、Nextボタンをクリック

5."I accept..."を選択して、Finishボタンをクリック

6.数秒間"Installing Software"を待って


7."Software Updates"でEclipseをリスタートするか?と聞いてくるのでYes
8.再起動後にForce.com IDEをインストール

今度は無事インストール完了しました。いやはや。

ところで、上の画面コピーが汚い件。

「このウィンドウだけスクリーンショットを取る」みたいなツールを入れてたはずですが、使い方をすっかり忘れてcmd+shift+4に頼ってます。

2012年10月20日土曜日

本気でTitanium mobile / ACS

■クロスプラットフォームでPush Notification必須■

会社でのアプリ開発、当初はobj-cで進めてましたが「Androidは?」という意見が出てきたので、大きな投資なしにクロスプラットフォームでのPush Notificationが使えるTitanium ACSを使うことになりました。

私、基本的にラクにラクに生きていたいのでインターフェースビルダのないツールってのは苦手なんすけど…でもHTML5+JavaScriptのPhoneGapよりJavaScript+NativeのTitaniumの方が大分サクサク動きますし、Sencha TouchほどではないにせよPhoneGapよりMVCをきれいに分離できるので、まぁいいや。

ただ、基本的にデモ程度しか作ったことがないので、ViewをフリップさせるのすらGoogle先生のお世話になりっぱなしです。

例えば、「キーボードが出てきたよ」というイベントや、その時有効な画面サイズを引っ張ってくることができない(obj-cでプラグイン書けば可能)ので、よくある「テキストを入力しようとすると適切な位置にTextFieldが動く…っていうアレを実装するのに一苦労する…というレベルです。

「obj-cなら…」というため息を抑えつつ仕事する今日この頃。

■ACSを使うには■

以前はti.cloud.jsを手動でコピーする等の手順が必要でしたが、最新のSDK 2.1では新規プロジェクトを作る際に「automatically cloud-enabled this application」をチェックすれば自動的にモジュールが読み込まれるようになりました。

ググって出てくる事例は、この辺がちょっと古いものもあるので、「本家ページ」を参照しながら読み進むと良いです。

これでcreateUser, loginまでは何の問題もなく進みます。強いていえば、サンプルのcreateLoginではパラメータとしてemailを渡していないことと、「Create Succsssが返って来ているのにACS Management側で登録されたデータが見えない」と思ったらmanagement画面のモードがDevelopmentでなくProductionになっていた、って2点ぐらいです。

■Chatメッセージを送ってみる■

本家掲載のサンプルを使って、ボタンをクリックするとメッセージを送信するテストをしてみました。なお、ここで一つハマったのは、idsです。usernameでもemailでもなく、user idを指定しなければいけません。

app.jsでログイン処理を書き、以下のコードを適当なwindow.jsに貼ります。


    var button = Ti.UI.createButton({
        top:100,
        width:50,
        height:30,
        title:'送信'
    });
    view.add(button);
    
    button.addEventListener('click', function(e) {
        var ids = ['ここはユーザID'];
        Cloud.Chats.create({
            to_ids: ids.join(','),
            message: 'Good morning'
        }, function (e) {
            if (e.success) {
                for (var i = 0; i < e.chats.length; i++) {
                    var chat = e.chats[i];
                    alert('Success:\\n' +
                        'From: ' + chat.from.first_name + ' ' + chat.from.last_name + '\\n' +
                        'Updated: ' + chat.updated_at + '\\n' +
                        'Message: ' + chat.message);
                }
            } else {
                alert('Error:\\n' +
                    ((e.error && e.message) || JSON.stringify(e)));
            }
        });        
    });


「送信」ボタンをタップすると数秒後「success」のアラートが表示されるはずです。

■ところで■

ACSはRESTベースのサービスです。
別にTitaniumに限定されているわけじゃないんですよね。

nativeだったら今頃は…。でも、このまま進みます

次回いつになるかわかりませんが、お楽しみに。

2012年9月21日金曜日

WebObjects + Heroku:その3・WOのWARを作る

■ProjectWOnderのセットアップ■

ここを参考にして進めます→「Project Wonder Installation

Step1-4までありますが、3まででOKです。「Step 4:  Import Project Wonder into your Eclipse workspace」はちょっと説明が必要なのでこの後の節で。

■WOnderのセットアップ■

大まかな手順は
  1. WOnderソースコードのダウンロード
  2. Java環境変数の確認と設定
  3. ビルド&インストール
です。前提として、以下の作業はhomeディレクトリ直下で行いますが、home下であればどこでも結構です。

まずはソースをダウンロードします。「Getting the Wonder Source Code」を参考にしました。

・Homeディレクトリへ移動
    $ cd

・WOnderソースコードのダウンロード
    $ git clone git://github.com/projectwonder/wonder.git WonderSource
    $ cd WonderSource

・最新版の確認とダウンロード
     $ git checkout integration


次に、javacの環境設定の確認です。ターミナルで
    $ setenv | grep JAVA_TOOL_OPTIONS
    JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF-8
    $

のようにエンコーディングが指定されていればいいのですが、ない場合には適当なエディタで.csrcを開き、 setenv JAVA_TOOL_OPTIONS -Dfile.encoding=UTF-8 と追加します。追加したらシェルを再起動します。ターミナルごと再起動するか新しいウィンドウを開いてもOKです。上記のsetenv...を使って、設定が反映されていることを確認してください。

では、ビルドとインストールです。ターミナルから
    $ ant frameworks; sudo ant frameworks.install

を実行します。数分かかりますが、エラーやワーニングが出ていないか注意してください。buildが終わったところで一旦動きが止まり、sudoのパスワードを求められます。最後に
    BUILD SUCCESSFUL
    Total time: 25 seconds

が表示されれば終わりです。こう書くとあっという間なんですが…いろいろ試行錯誤があって数日ツブれました…いや、愚痴ですけどね。

■WOアプリを作る■

ではいよいよWOのアプリを作ります。

Eclipseで File>New>Wonder Application を選びます。Wonder Applicationが選択肢として出てこない場合には、PerspectiveをWOLipsに切り替えてからもう一度。プロジェクト名は WOHeroku にしてFinishボタンをクリックします。

プロジェクトを開き、Sources>your.app>Application.javaを右クリックし、Run As>WO Applicationを選びます。


コンソールに起動ログが真っ赤な字で表示されますが、お気になさらず。そのまま数秒後ブラウザ上に Hello World が表示されます。これでWOアプリが動くことは確認できました。


■ServletとしてDeployし、Herokuへ■

プロジェクト名を右クリックし、Properties>WOLips Deploymentを選びます。ここで「Servlet Deployment」と「Autogenerate web.xml」をチェックし、OKをクリックします。この時点でHerokuで動かせないことに気づきました。SDDオプションがありません。SDDでないとWOFが組み込まれないので…。

プロジェクトメニューを右クリックし、WOLips Ant Tools>Installを選びます。ビルドが行われますが、通常のビルドよりも時間がかかります。問題がなければ数分後、BUILD SUCCESSFULの表示が出てApplicationディレクトリにWOHerokuとWOHeroku.woaディレクトリ, WOHeroku.warが出来ているはずです。


が、私の環境もそうでしたが、/Library/WebObjects/Applicationディレクトリのパーミッションがユーザに対して許可されていないとBUILD FAILEDになります。対処方法は二つ、開発マシン上なら1、運用マシン上でビルドも行うのであれば2でしょうか。

1.パーミッションを変更する


標準的なインストール環境であれば、ターミナルで
    $ cd /Library/WebObjects/Versions/WebObjects543/Library/WebObjects
    $ sudo chmod 775 Applications/
    Password:
    $ sudo chgrp staff Applications/

などと設定します。ともかく、自分がApplicationに書き込みできるような権限を付与します。775とは古いねしかしorz

2.インストール先を変更する


プロジェクトWOHerokuディレクトリの直下にある build.properties に dist.dir=dest という一行を追加します。こうすると、ビルドした結果がWOHerokuディレクトリ直下のdestディレクトリに変更されます。

これでWOHeroku.warができました! ここまでホントに長かった…。

■HerokuへDeployment、できません■

ターミナルで、WOHeroku.warのあるディレクトリへ移動し、デプロイします。

    $ heroku deploy:war --war WOHeroku.war
     !    No app specified.
     !    Run this command from an app folder or specify which app to use with --app <app name>
    $
    $ heroku deploy:war --war WOHeroku.war -app WOHeroku
     !    No app specified.
     !    Run this command from an app folder or specify which app to use with --app <app name>
    $

と、いうことでapplicationとして認識してもらえません。mavenさんでWOFも送り込むようなpom.xmlを書いたりすれば技術的には可能だと思いますが、これからmavenさんを勉強するスキルがありません。

ごめんなさい。

ただ、今後もWOを趣味程度にいじっていこうと思ってます。最近会社にもMacが入ってXcode三昧だったりするので、家と会社では違うことをやらないとね。

2012年9月20日木曜日

WebObjects + Heroku:その2・WARを直接Herokuへ

■前回の続き■

前回はHerokuのアカウント取得、RubyサンプルのHerokuへのデプロイ、Tomcatのインストール、TomcatサンプルのHerokuへのデプロイ…まで済ませました。今回は下記の通り、ローカルでビルドしたWARを直接Herokuへデプロイして動かすところまで。

  • Eclipse+Tomcat
  • TomcatプロジェクトからWARを作成
  • HerokuへDeployment

■Eclipse+Tomcat■

EclipseでTomcatアプリ開発」を参考にしました。うーむデザインに時代を感じる…。

大まかな流れとしては、
  1. EclipseにTomcatプラグインを入れる
  2. EclipseからTomcatが起動・終了できることを確認する
  3. 新規にJava/Tomcatプロジェクトを作り、上記サンプルソースを貼ってEclipseのDebugまたはRunボタンをクリック→コンソールにエラーが出ないことを確認
  4. ブラウザでhttp://localhost:8080/アプリ名/servlet/helloを表示し、Hello, World!
最後のところでURLでちょっとハマりました。TomcatのManager画面にはアプリ名が表示されているのですが、そこをクリックしてもnot foundになってしまう。てっきりTomcatの設定の問題かとあちこちググったりしても思い当たらない。で、上記のページをよく見直したら、URLはアプリ名+web.xmlのurl-patternになっていました。素人はこういうところでハマるから困ったもんです。

ともかく、EclipseでTomcatアプリを作って動かすところまではOK。

■TomcatプロジェクトからWARを作成■

Tomcat JavaプロジェクトをWARにするのは:
  1. プロジェクトを右クリック>Properties
  2. Tomcat>WARエクスポート設定タブ

ここで「エクスポートするWARファイル」の出力先パスを指定します。私の環境ではなぜか「参照」ボタンからファイルダイアログを指定してもパスを選べなかったので、出力先をフルパスで入力し、OKをクリックします。

なお、「.javaファイルをエクスポート」してしまうとソースも一緒にエクスポートされてしまうのでご注意を。それにしても私の環境は日本語化していないのに、どうしてここだけ日本語なんでしょ?


続いて、プロジェクトを右クリック>Tomcat プロジェクト>


を選びます。さっき指定したところにWARができているはずです。


ということで、このwarを直接HerokuへPushします。

■WARをHerokuへDeployment■

参考にしたのはここです→「Getting started with WAR deployment on Heroku

記事にもありますが、Heroku toolbeltのインストールとHeroku Accountが必要です。またHerokuのバージョンは2.24.0以上が必要です。

まずツールをセットアップします。これはターミナルで以下の通りタイプするだけです。
    $ heroku plugins:install https://github.com/heroku/heroku-deploy

あとは、さっき作ったTestTomcat.warの置いてあるディレクトリに移動してから、HerokuにDeployするだけです。
    $ cd
    $ heroku deploy:war --war TestTomcat.war
    $ heroku open

…ここでブラウザが開きますが、エラーが出ます。


泣いてはいけません。ローカルで走らせた時と同様にブラウザ上のURL末尾に /servelet/hello/ を追加して再表示します。今度こそHello Worldが表示されます。って書くと2行だけど、実際は/servlet/hello/をすっかり忘れてて数時間グーグル先生と旅をしていまいたorz

ということで、次回いよいよWebObjectsのWARファイルを作って、Herokuへデプロイします。その前にPostgreSQLに対応したTomcatサンプルを作ってHerokuで動くことを確認したら?という声が聞こえますが、TomcatでのDB取り扱いを勉強しても将来おそらく使うことはないと思うので省略します。

その1でも書きましたが、WOはHerokuにはデプロイはできません。ただ、日本語のMac環境にWonder framework入れようとするとコケるので、その辺の情報提供としてその3を公開します。

2012年9月16日日曜日

WebObjects + Heroku:その1・準備編

■残念なお知らせ■

HerokuにWebObjectsを載せることはできませんでした。ということで、この記事はHeroku超入門+WOLips超入門です。夢を見せてくれてありがとう…Single Directory Deploymentがサポートされていないとは思わなかったよ…。

■何を今更WebObjects■

「Herokuに対して直接WARをデプロイできる」ということを知ったのがキッカケでした。

Rubyに馴染みがないのでHerokuには触っていなかったのですが、Javaなら何とかなるしEclipse使えば必要最小限の作業でWARを吐き出せますからね。で、どうせWARを作るのであれば好きなフレームワークで試そうと思った次第です。

会社の仕事ともぶつからないし。

でもいきなりHerokuでWOを動かそうとしても上手く行かなかった場合に原因の切り分けが難しくなるので、1)まずHerokuを試し、2)TomcatのWARを作ってHerokuにデプロイ、3)最後にWebObjectsでWARを作ってHerokuで動かす…という段階を踏みます。

■Herokuとは■

HerokuはPaaSです。Ruby, Scala, Node.jsなどで書かれたプロセスをクラウド上で走らせることができます。バックエンドサービスとしてPostgresSQL, Hadoopなども使えます。1プロセスの起動時間(CPU時間ではなく起動している時間)として750時間、PostgresSQLの容量5MBまで無料で使うことができます。

詳しくは「FAQ:Herokuってなに?メリットは?」をご参照ください。

■Herokuアカウント取得■


Heroku.com」ページの右下にある「Sign up」をクリックします。日本の美しい風景が描かれたSign upページからemailアドレスを入力すると、招待メールが届きます。

メール上のリンクをクリックしパスワードを登録するとめでたくheroku Dashboardが表示されます。

左側にある「Download Heroku Toolbelt for Mac OS」をダウンロードしておきます。herokuコマンドラインツール, gitその他がインストールされます。インストールが終わったら、画面右側にあるようにheroku loginとタイプし、emailとpasswordでログインします。その次にherokuとの通信のための秘密キーを何にするか尋ねてきますので、番号で指定します。もしssh public keyがないと言われたら、KeyChainを使って作成してからもう一度。作成した後で
    $ heroku keys:add
を実行してキーを登録します。

確認のために画面下にあるコマンドを試してみます。Rubyのサンプルをgithubからとってきて、Herokuに上げます。

なお、4のところでRSAのパスワードを求められますが、間違えると以下のようメッセージが出て先に進めなくなります。
    Permission denied (publickey).
    fatal: The remote end hung up unexpectedly

その場合は間違ったキーを削除します。まず、以下のコマンドでKey名を表示し
    $ heroku keys
ここで出てきたkeyを
    $ heroku keys:remove keyname@domain
で削除し、下記コマンドで別のキーを登録しなおして
    $ heroku keys:add
もう一度4を実行します。間違えると勉強になるわ(泣

ともあれ、これでHerokuを使う準備ができました。Heroku Dashboardをみると、アプリが動いていることがわかります。アプリケーション名のリンクをクリックして、アプリケーション情報のページからOpen Applicationをクリックします。別ページが開いてHello, Worldが表示されればOKです。Herokuを無料で使えるのはWeb Dyno1本=インスタンス1本ですので削除しておきます。Settingsページの一番下からRemove Appしておきましょう。まぁ起動時間単位の課金なので、そんなに神経質になることもないのですが。

■HerokuのためのTomcat環境とサンプルを準備■

ここを参考にしました→「HerokuにEmbedded TomcatヘJava Web Applicationを作る

ただし、ここに掲載されているpom.xmlは壊れていてソースファイル名などにも記述漏れがあるので、上記記事の原本「Create a Java Web Application using Embedded Tomcat」からpom.xml, Main.java, HelloServlet.java, index.jspを拾ってきました。

ついでにTomcatも新しいのをインストールしなおしました。この辺が参考になりました→「[Tomcat]MacでのTomcatの環境構築」。最新は7.0.30ですが、Eclipse Tomcat pluginが対応していないので6.0.35を入れてください。

コマンドラインからsh target/bin/webappを実行してからブラウザでhttp://localhost:8080/を開き「Hello, Heroku!」の力強い文字w表示されればサンプルアプリの準備はOKです。ターミナルでctrl+C、ローカルで動いているアプリを止めます。

これで一応、ローカルでTomcatが動くようになりました。

■サンプルアプリをHerokuへ■

引き続き上記のページを参考にしながら、アプリをHeroku上で動かします。上記英語ページの「Deploy your application to Heroku」あたりから。同日本語ページにも記述があるのですが、ちょっと読みにくいかな…ともかく、あとはProcfile, system.propertiesを作ってコマンドをいくつか打ち込むだけです。最後のheroku openを実行すると、ブラウザ上にさきほどと同じ「Hello, Heroku!」が現れるはずです。お疲れ様でした。

■次回は■

慣れた人なら2-3時間でここまで来られると思うのですが、いくつかハマってしまって丸1日かかってしまいました…。

ということで、次回Tomcatアプリを作り、WARファイルを直接HerokuにDeployします。

2012年9月15日土曜日

FlexでFacebookアプリを作ろうとして挫折

■発作的にとりあえずやってみた■

初めてのFlexおよびFacebookアプリケーションの作成 – パート1:ローカルでのビルドとテスト

以下パート4までありますが、執筆者の肉食系キメ顔にびびらないで続ければ
  • Facebookアプリを登録
  • Flex/AIRで作ったアプリから氏名、誕生日、ステータスなどを取得
  • 同 メッセージをポスト
  • 同 アプリをデプロイメント
  • AIRアプリをFlashに変更
  • Facebook上でFlashが動くように処理

というところまでさくさくたどり着けます。このチュートリアルはとてもよく出来ていて、APIなどの探し方まで示してくれてます。素晴らしい。

ここまでは順調でした。

■Graph APIで大ハマり■

さて、Facebookアプリというからには、独自のプロパティに書き込みができないといけません。これについて上記チュートリアルには記述がありませんので、自力でなんとか。

まず、例によってfacebook developerページからオープングラフ>Getting Startedを選び、ActionとObjectを登録し「スタート」ボタンをクリックします。

この辺は「FacebookのOpen Graphアプリを作り App Centerに登録するには」が参考になります。言語は違いますが、とりあえずfacebookへの登録方法やAPIの構成は同じですので。


そんなこんなで、上のようなOpen Graphを作りました。で、画面の左側をみるとGet Codeというのがあります。ここを参考にすれば良いのかと思ったのがハマりの最初。こんなコードを書いて見たものの、エラーで先に進めません。


var data:Object = new Object();
data['fb:app_id'] = "xxxxxxxxxxxxx";
data['og:type'] = "taretest:bp_high";
data['og:title'] = inputTitle.text;
data['og:description'] = inputDescription.text;
FacebookDesktop.api("/me/taretest:record",submitPostHandler, data, "POST");

結局、これは完全に勘違いでした。以下のコードでとりあえずエラーは出なくなり、数値データは書き込まれないもののactivityとしてFacebookのタイムライン上に表示されるようになりました。

data['bp_high'] = 'http://samples.ogp.me/yyyyyyyyyyyyyyyy';
FacebookDesktop.api("/me/taretest:record", submitPostHandler, data, "POST");

ちなみに以下はどうやってプロパティを指定すれば良いか試行錯誤した痕跡です。書き込む側が悪いのか、表示するための設定が悪いのか…その辺はまた明日。

data['bpHigh']           = '1';
data['bpLow']            = '2';
data['bp_High']          = '3';
data['bp_Low']           = '4';
data['taretest:bp_High'] = '5';
data['taretest:bp_Low']  = '6';
data['bp_high:bpHigh']   = '7';
data['bp_high:bpLow']    = '8';



■凡ミスで大ハマり■

しかし、朝、作業を再開しようとするとFacebookDesktop.initとloginが失敗するようになってしまいました。リポジトリから古いソースを引っ張り出してもダメ。Macを再起動してもダメ。

いろいろ調べたところ、「アカウントでアプリを削除すると、トークンが無効になってしまうので取り直さないとダメ」ということが判明。そういえば、ゆうべ寝る前にテストデータが山盛りになってしまったアプリを「一度消しておくか」と気軽に削除したのでした。これが原因。

さて、それから、登録されてしまったトークンを削除する方法を探したのですが、SDKのAPIにはそれらしいものは見つからず、おそらくSharedObjectとして保存されていると思うのですがファイル名が暗号化されているので見つからない。

新しいFacebookアプリを作ったら動きましたがそんなのは解決策じゃないし、とりあえず先に進んだとしても本気でアプリ作った時に同じコトでハマる可能性大なので、とりあえず対処方法が見つかるまで保留することにしました。

とほほ。まぁ、でも、「AIRでFacebookアプリ?できますよ!」とか請けちゃってからハマるよりかはマシ…とポジティブに考えておきます。ポジティブでもないか。

では、またいつか。

2012年9月10日月曜日

急に思い立ってFacebookデベロッパー方面

何がきっかけになったのか忘れたけど、自宅で勤務時間外に(←ここ重要)何かググっていたら「Facebook and Heroku: an even easier way to get started」てな記事が出てきて、そこから「初めてのFlexおよびFacebookアプリケーションの作成 – パート1:ローカルでのビルドとテスト」とかFacebook SDK for iOS Tutorialてな方向に飛んだら眠れなくなってしまったw

とりあえず、「Facebookアプリは比較的簡単に作れるけど、さてHTMLやらコンテンツをどこに置いたらいいのさ」ってあたりは今や選択肢が多すぎて困ったもんです。今お金を払っているサービスに乗っかるのが一番ラクなんですが、iCloudもWebホスティングやめちゃいましたしねぇ。あとはGoogleの倉橋屋ドメインのWebホスティングかしら。

それに関連してherokuも見ています。herokuはコンテンツ上げられない(できないわけじゃないけど、トラフィック課金を回避するためにもただのビットマップなどはCDNなどを使うのが無難)のがちょっと面倒ですが、それ以外というかheroku本来のPaaSは大変に魅力的だし、Facebookと戦略的提携をしているので何かとラク。

とりあえずFacebookアプリとしては、

  • Flex+Salesforceの業務系アプリ
  • 自転車トレーニング系アプリのiOS版とFlex版
このあたりを作ってみようと思ってます。

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年8月16日木曜日

SplitViewControllerで右へのSwipeが効かない

iPad用のデモアプリをMaster-Detailテンプレートから作っていて、Swipe Gesture Recognizerを貼った。実機で試すと右へのSwipeが認識されない。

1時間ぐらいバインド先や順番を変えてみるなど試行錯誤するものの結果は変わらない。

試しにSingle Viewで試すとうまく認識される。

ググったら、Stack Overflowで同じ現象に悩んでいる人が見つかった。

結論:iOS 5.1のバグでした。

デモアプリはSplitViewControllerを使わない方向で作ることにした。単純なView上にTableとViewを並べるという原始的解決法。UITableViewControllerが使えないと何かとめんどくさいけど、そこは根性でカバーしますよ。とほほ。

2012年8月11日土曜日

カレー同期


■現象■

昼ご飯外でカレーライスを食べて帰ったら、家の夕食もカレーだった

■推定理由■

前日近所の家がカレーだったんじゃないだろか。その匂いをかいで、(ああ、そういえばしばらくカレー食べていなかったなぁ)と思って、翌日の昼食と夕食に反映されたんじゃないか。

…と思う。

■余談(後日加筆)■

このブログへのアクセスは知人とあとクロウラーぐらいかと思っていたんですが…このネタへのアクセスはほぼゼロだったので「ああ、検索エンジンなどから調べてここに来てくれた人もいるのだな」とわかりました。

さらに関係ないけど、AdSenseの設定がわからん…。

2012年8月10日金曜日

PhoneGapってかCordova 2.0.0

2.0になってインストール方法が少し変わりましたね。

とりあえず、今週末にLion上にインストールして試してみる予定です。

どうせまたハマると思いますので…お楽しみにorz

2012年7月12日木曜日

ADT 20でプロジェクトが作れない

会社のLionにAndroid開発キットをインストールしました。EclipseはForce.com IDE用にすでに入れてあったので、adnからインストールし、SDK ManagerからAPI 8, 10, 15、それにIntel HAXを選択。

さて、Hello worldを…と思ったら、Android Application Projectで、最後のFinishが押せません。いや、押してもすぐに戻ってきてしまって終わらない。

ググってみると、どうもADT 20の問題みたいで、いろいろwork aroundが出ている。

  • android-sdk-macosx/extras/compatibility -> supportにrename
    • すでにsupportだった
  • sdk managerからsupport libraryを削除してもう一度create new project、ライブラリがないって言われたらそこでinstallをクリック
    • 変化なし
でも、結局、症状は同じでした…。ADT 20よりも古いツールからインストールしていたマシンでは問題ありません。

とりあえず、当面Androidいじる予定ないから良いんですが…何とか早く解決してほしいものです。また何か思いついたら対策してみます。

2012年7月10日火曜日

会社にMacが来た! ・その後

標準の500GB HDDをPlextor PX-256M5Sに換装しました。外付けUSBは禁止されているので、東映のアダプタを使ってDVD Driveのところに500GB HDDをセットして移行完了。やー、廉価版SSDとはいえ、HDDとは比べものにならないぐらい爆速ですね。立ち上がりが早すぎてXPのスリープ復帰より早いです(いやマジで)。移行が終わったところで、またHDをDVD Driveに戻しました。
外したねじ置き場。まぁ右奥3本が長いだけですが。
Excelとかパワポを使わずにはいられない会社なので、BootcampにWindows7を入れました。

ツールでパーティションを切って、Windows7のDVDを入れて待つことしばし。ってか、「展開中xx%」で止まること3度。00%, 53%, 68%だっけかな。68%では30分以上止まっていたのでWindowsに詳しい人に「もうリセットしちゃおうかしら」って話に行って戻ってきたら進んでいたというオチ。しかし、インストール後、Bootcampはそのままでは暗号化できず、暗号化しないと会社の規則で持ち出せず、暗号化するとVMWareからは起動できなくなる、ということで没。

再びBootcampツールを使って、パーティションを消す。サイズを変えることはできないけど、消すことはできるのね。で、改めて、VMWareでインストール。そしたら、CPUを2個しか割り当ててないのに8分でインストール終了。さっきの「展開中」は何だったんでしょう。

MacのパーティションはFilevault 2で暗号化済なのでその上のVMWareもセキュリティ的には問題ない。ただ、MacOS上にもWindows上にもSymantec EndProtectionを入れたらとても重い。特にMac側でファイルをダウンロードした後のスキャンが異様に遅くて泣けます。Mac界で比較的評価の高いSophosとかじゃダメか聞いてみようと思います。

さて、あとは入社以来使っていたXP(Core 2 Duo / 2GB / HDD 64GB)の中身を載せ替えれば移行完了です。

インストールが一段落したら、もう一度DVD-DriveをHDDに換装して、HDDをTimeMachine用に使おうと思ってます。実は今回、超お買い得なRetinaを諦めた理由の一つがこれです。セキュリティのため普通の会社ではプロテクションのない外付けUSBは禁止されていると思いますが、TimeMachineなしでMacを使うのも不便、ならば無理矢理2スピンドル化して使おう、というココロです。

まぁTimeMachineも暗号化できるので、そこを説得できれば良いのかもしれませんが、説得するのめんどくさいのよ。

2012年7月6日金曜日

会社にMacが来た!

そういえば、このブログのタイトルには「MacもGoogle docも使えないのでここに書く。会社をやめる理由はたぶん『Macが使えないから』になる予定w」とか書いていたのですが、MacBook pro 15" mid 2012さんが来ちゃいました。

Symantecさんを入れなければいけないなど、いろいろ制約もあるのですが…ともかくきれいなフォントを見ながら仕事できるだけでもうれしいざます。

でも、「Macは印刷業界ぐらいしか使えないじゃんw」という古い人もまだまだ多いよね。実際のところ、Macとは関係ない技術会議でもほんと冗談みたいにみんなMacBook Airだもん。先日の「ヒッグス粒子発表か?」を取り上げたニュースでも、技術者が使っているのはMacばっかりだったし。Salesforceの中の人も技術職はAirがやったらと多い。

スライド上映中に会場に浮かびあがる無数のアップルロゴ、こんな日が来るなんてちょっと感無量ですわ。

というわけで、今後もこのブログは続きます。

2012年7月3日火曜日

Painless Mobile App Development Webinar


Facebookのタイムラインに新しいWebinarが出てました。しばらくForce.com Mobile SDKをアップデートしていなかったのですが、いろいろ変わっていました。Webinarの中身を紹介します。英語力ほぼ皆無なので聞き違えていたりするところがあればご指摘ください。なお、私の主観的なコメントは黄色で表示しています。

  • Database.comに関して
    • Database.com概要
    • Apexの流し込み
    • workbenchの使い方(SOQL、REST APIのURLの作り方)
  • ここで急におっさんに声が変わって、Mobile SDKの説明に
  • まずMobileSDKの技術要素の説明(Push notification対応してたんだなぁ)
  • Native/Hybrid/HTML5の位置づけ
  • mobile SDKはOpenSourceで開発されている
  • OAuthについての説明
    • 認証不成立時のスライドになぜか日本のファミリーマートが
    • OAuthの各Flowについて
      • UserAgentfFlow/RefreshFlowの動作フロー
  • 実際にXcodeを使ってのデモ
    • SDKのインストールが結構めんどくさいのだけど、そこは省略
      • みんなそこでハマったことがあると思うんだけどなぁ
    • NativeProjectをスタート
    • ハマりやすいRemote Access設定についての説明がわりとしっかり
    • build&run→User-Agent FlowのOAuthがしっかり動作。良かった良かった。
    • ソースを読んでいく
      • やっぱりまだStoryboardには対応していないんですね。
      • view controllerについての説明など。
  • RESTについての説明。
  • 28分頃、オンラインでのSOQLクエリについての説明
  • その下にオフラインのサンプルが出ている。
    • あとで読もうと思う。
    • クエリとJSONの対比。
    • JSONでの戻りの説明。
    • JSONからtableへデータをセット。
  • SmatStoreはオフラインでの動作をサポートするメカニズム
    • SQLiteとJSONベースのdocument store。
    • device level hardware encryption対応
    • SmartStore Phonegap Pluginが用意されている
    • SQLCipherにも対応。
  • HyblidはJASONベースのみ。
    • ブラウザ組み込みSecure SQLのサポートの関係で?
  • 36分あたりからSecureなJASONベースのストレージについて
    • Newton 'Soups'な話がでてきた。懐かしい。
    • 使い方についての説明。
    • サンプルではrequest:didLoadResponseでSoupと同期をとっている。
    • Soapに対するQueryについて説明。
  • 各リソースについて紹介
    • サンプルはこれ。
    • https://github.com/tomgersic/CrumpRealEstate
  • Q&A
    • Upsertした場合の同期について質問が出ていたけど聞き取れない。


だいたいこんな内容です。Androidでの開発は出てきませんし、Hybidについても概要だけで実例のデモはありません。

すでに開発経験のある人の場合、とりあえずSmartStoreについての概要を把握するのに良いかもしれません。これからiOS+Force.comで開発しようという方は、もしハマったら私の過去ログなどでインストール方法を確認してみてくださいませ。

2012年7月1日日曜日

jQueryで一部ページだけローテーション禁止にする

この週末、同僚氏からの質問を受けて、ちょっと調べてみました。

結論としては、無理です。mobile Safariが対応していません。jQuery/PhoneGapでは1つのアプリを1本のhtmlで処理しますが、htmlごとなら「ロックする/しない」を設定できるものの毎度おなじみの<div data-role="page">のブロック内だけで切り替えることはできません。

ただ、まったく方法がないわけではなくて、一つは、PhoneGapのプラグインをobjective-cで書いて、まいどおなじみのこれを実行する方法です。たぶんこれが正攻法。

 (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return NO;
}

もう一つは「ローテートしたら無理矢理view内部を逆方向に90度ローテートして打ち消す」という力業。ここのページの一番下にコードが出ていますが、iPhoneを回転させると、追従して回転した後でまた無理矢理元に戻るところがいとおかし。

ということで、jQuery mobileでアプリを作る場合は、「一部だけ回転禁止はできないよ」ということを念頭においといた方が良いですね、というお話でした。

基本的に役に立たない情報ですいませんm(_ _)m

2012年6月17日日曜日

Dreamweaver CS6 + PhoneGap 1.7

表題の通り、DW CS6を使い始めています。まぁ無料評価版ですが。なんかものすごい重いけど、それはまぁ最新のMacなら問題ないのでしょう。

で、今日はさくっと簡単にアプリをiPhoneの上で走らせて、そこまでの紆余曲折なんかも公開して、「いやー、ちょっとハマりましたけど、簡単ですね。はははははは」とか書こうと思っていたのですが、最後の最後、iPhoneにインストールするところで失敗してしまいます。

Androidはエミュレータ上で普通に起動するんですが。

というわけで、表題のDreamweaver CS6 + PhoneGap 1.7>iPhone4については、また今度の週末チャレンジ致します。

それにしても、これまでPhoneGap苦手ってかJavaScript苦手なんであんまり触っていなかったんですが…覚えることがたくさんあり過ぎて涙目です。

いや、まだ別にPhoneGapで行くと決めたわけではないのですが。

2012年6月9日土曜日

Salesforce季節の変わり目にありがちなこと:APIが違う

さてもうすぐSummer '12です。

新規に取得したDev環境はSummer '12になってますね。その上で一部リリースされた新機能を試したりチャットのポップアップがうぜぇwなどと言いつつ作業し、できあがったパッケージを本番環境に移そうとしたのですが…「API違うから駄目っすw」と言われました。

パッケージもForce.com IDEも駄目。同じことをSpring '12の時期にもやっていたような気がする…でも、Dev環境取得する時点でAPI選べないのでどうにもなりません。

で、エラーを細かくチェックしていくと、

  • カスタムオブジェクトやレイアウトに関しては移植可能
  • エラーが出るのはVisualforce, Apex, Triggerなどのメタファイル

という状態でした。

ということでwork around。

  1. 稼働環境用サンドボックスへカスタムオブジェクトやレイアウトをすべて移植
  2. 同サンドボックスへ手動でVisualforce, Apex, Triggerをコピペ
  3. サンドボックスから本番環境へDeployment
まぁ当たり前の手順ですけども、ハマった方のご参考になれば幸いです。

なお、今回ソース数本だったので手動で対応できましたが、本数が多いと依存関係もあって大変です。とりあえずは以下の順番でコピペしてみます。
  1. Trigger
  2. 通常のApex
  3. Visualforce
  4. テストコード
ひっかかったら適宜入れ替えます。また、どうしても依存関係が解消できない場合には、先にクラス名定義だけコピーしておいて、あとから実装部分をコピーするという方法もあります。最後の手段として、ソースの数だけブラウザにタブを開いておいて、依存関係のないところから片っ端からQuick Saveして少しずつ埋めていく、なんてのもあります。

申し遅れましたが、この手の作業はForce.com IDEよりもブラウザ経由の方がレスポンスが良くて作業しやすいような気がします。

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年4月7日土曜日

Androidアプリを書いて見た。



会社でAndroidアプリを書いてみました。PhoneGapなどに頼らないで、nativeなforce.com対応アプリ。書いたと言っても、Force.comのテンプレートをベースにして、Chatterとコメントを表示するだけですが。環境を整えるのに2時間、Chatterとコメントが出るようになるまで1時間。

で、感想:

  • エミュレータが超重い
  • APIなどが単純でわかりやすい
  • エミュレータが糞重い
  • やっぱりEclipseはJavaで使う分には開発環境だな
  • エミュレータが馬鹿重い
  • iPhoneのInterfaceBuilder最強(今はXcodeに統合されてるけど)
  • エミュレータが劇重い
ってところですかね。「また別のAPI習得するのは私の脳には無理だからPhoneGapにしとこう」と思ってたんですが、いつまでも好きになれないJavaScriptよりも手に馴染んだJavaで単純なAPIを相手にしている方がラクかなとも思ってます。

ツールの圧倒的な操作性の良さとAPIの美しいiOS、単純なAPIとクラッシュしても必ずエラーが出てくれるAndroid。自宅ではiPhone、会社ではAndroid…まぁ良い感じかな。

で、問題のAndroidのエミュレータですが…会社のPC(Core i2, 2GB,HD)が終了しなくなってしまうのは何故。

とにかくエミュレータには困ったもんです。Android x86入れたくても会社のPC(しつこいが今時Core i2, 2GB,HD)じゃ無理す。7980円の有線LAN仕様Android買うかなw

追記(2012/04/10):
在宅勤務用のCore i5, 3GB, Windows7だとエミュレータは何事もなかったかのように無事終了してくれます。今後Android開発はこっちでやろうっと。

2012年3月28日水曜日

iPhone対応Force.comアプリをiPadでも


■iPhoneアプリをiPad対応に■

Force.com iOS SDKのnativeテンプレートは、iPhone / iPad両方に対応しています。

ただ、iPad版はMaster / Detailが前提。しかし私の作ったFourChatterはChatterがソースなもんで必ずしもきっちりMaster / Detailがあるわけではなくテンプレートのままの形態では動かすことができません。というわけで、当初はdisabledしてました。

しかしそのままというのも何だし、このところまったく開発が止まってしまっているのも何なので久しぶりに手をいれてiPad対応にしてみることにしました。


■経緯■

新しくiPad用のStoryboardを作り、プロジェクトに登録。 iPhone用のStoryboardを別ウィンドウで開いておいて、見比べながらviewをぽちぽち置いていく地味な作業を約30分。とりあえず、iPad上でもRoot Viewが動くようになりました。

で、StoryboardにCommentViewを追加したら…見事にハマりました。

…ってか、このブログハマってばっかりだよなorz


■症状■

症状としては、RootViewだけでは動いていたのにCommentViewをStoryboardに追加しただけでRootViewすら出てこなくなりました。SIGABRTです。そこから約2時間、Assembler上をシングルステップで追いかけてみましたが、どーにも見つかりません。念のためiPhoneで試してみると、動きます。 まぁこの場合、動かなかったら泣きますけどね。


■解決■

最終的な原因は、テンプレートのAppDelegate.mにありました。ここで「iPadだったらsplitViewをどうたら」という処理をしています。そうです、そんなものはとっくの昔に消しちまいました。ということで、この辺をコメントアウトして無事動くようになりました。

で…リリースしようと思ったんですが…FourChatterのウリは「iPhoneの向きを変えるだけでさくっとキーワードを切り替えてChatterを検索できる」っていうところにあります。しかし、iPadをぶんぶん回すとバカみたいという問題があります。私のiPad(初代)は回転ロックしちゃってるしね…。

というわけで、やっぱりiPhoneにはiPhone、iPadにはiPadに向いたGUIがあるよなぁ…というのが結論です。

さて、どうしましょう。タブで切り替えるか、任意の個数のキーワードを登録してタップで切り替えられるようにするか…。ただ任意の個数ってことになると「Four」Chatterっていうアプリ名が意味不明になるわな(4方向のfourです)。

--

でも今四十肩が痛くて新しいGUIのあるべき姿、みたいなことが考えられない。

…これを「四十肩ぐらいでw 言い訳にも程があるww」と思ったヒトは、本当の四十肩の怖さを知らないのだよ。寝返り打つたびに目が覚めるし、何かにつまずいてうっかり手を撞こうものならその場にしゃがみ込むほど痛いし。消炎鎮痛剤効かないし。今も何もしてないのに痛いし。

……以下、記事本体よりも長くなりそうなので省略。とにかく痛いのだ。

この記事を、とび職なのに四十肩でも仕事を休まなかった亡父に捧げます。

四十肩には効かないけど便利なので愛用

2012年3月18日日曜日

MySQLとDatabase.com

■予告と違いますが■

以前からぼちぼち書いていたこっちの記事が先に出来上がったので公開します。


■そのまま比較するのはいくら何でもアレですが■

今まで15年ぐらいMySQL使っていたと思うのですが、今日はじめてMySQL Workbenchを使ってみました。例によってマニュアル読まないのでとっつきにくかったけど、馴染んでしまえば楽勝。やっぱローカルサーバはサクサク動いていいですわ。

Salesforceは、というか、やっぱりWebアプリって、どうしてもサクサク感が足りない。日本にデータセンターできてWebでのレスポンスはよくなったものの、それでも「query」っていうレスポンス感ではないように思います。

Amazon RDSなどクラウド上で動いているMySQLサービスなんてのもあるけど、あれはどうなんでしょ。使ったことのある方いらっしゃいます? まぁ素のqueryとユーザ権限などてんこ盛りにかぶさったForce.com APIを同列に比べてはいけませんけども。


■Force.comからmySQLへ■

先日、Force.com APIで動かしていたFlashアプリをMySQLに移行するというお仕事をしました。一応、互換レイヤを作っておいてサクっと移行のはずですが予期せぬデータ変換トラブルが出るのは業界のお約束でございます。「お約束」ではすまない、とても大変なことになったのですが、その辺は長いので省略。関係者の皆様に改めて御礼とお詫びを申し上げる次第でございます。

その経験を元に、FlashでForce.comあるいはmySQLをアクセスしまくる方法、について簡単にまとめてみたいと思います。


■使用ライブラリ■

以下のライブラリが必要です。swcをダウンロードしてAIRプロジェクトのlibsに入れます。



■Connection/AsyncResponder■

割と似てます。当然Force.comではサーバ指定とポート指定は不要でid, passwordを渡してやればつながります。

mySQL:
mysql = new com.maclema.mysql.Connection("<サーバ>", 3306, "<接続名>", "<ユーザ>", "<パスワード>");
mysql.addEventListener("connect", handleConnected);
mysql.addEventListener("ioError" , errorConnected);
mysql.connect();

..

private function handleConnected(e:Event):void {
    trace( "connection success" );
}

..

private function errorConnected(error:Event):void {
    trace( "connection error" );
    trace( e.toString() );
}

Force.com:
var lr:LoginRequest = new LoginRequest();
lr.username = "<force.com id>";
lr.password = "<password><signature>";

lr.callback = new com.salesforce.AsyncResponder(loginHandler, faultHandler);
force.login(lr);

..

private function loginHandler(result:LoginResult, inObject:Object):void {
    trace("login success");
}

..

private function faultHandler(result:Fault):void {
    trace(result.faultcode);
    trace(result.faultstring);
}

何かするごとにAsyncResponderで成功時と失敗時のコールバック関数を渡してやるのも同じです。

Force.com/mySQLを一本化する場合に一つ問題があります。それは、asSQLはmx.rpc.AsyncResponderを使いますが、Force.comは同じ名前のcom.salesforce.AsyncResponderを使うという点。名前が違うだけなら、宣言と生成でフルパス指定すれば済むんですが、困ったことにコールバック関数の引数の数が違います。もちろん1本のソースコードでmySQLとforce.comに対応、なんてことをやらなければ全然問題ないんですけども。


■Fetch■

MySQL:
var st:Statement = mysql.createStatement();
st.executeQuery("SET NAMES 'UTF8'");
st.sql = "SELECT Id, Name FROM SomeTable__c";
var token:MySqlToken = st.executeQuery();
token.addResponder(new mx.rpc.AsyncResponder(queryHandlerSomeTable, fault, token));

..


private function queryHandlerSomeTable(data:Object, token:Object):void {
    var rs:ResultSet;
    rs = ResultSet(data);
    while( rs.next() ) {
        trace(rs.getString("Id"));
        trace(rs.getString("Name"));
    }
}


Force.com:
strQuery = "SELECT Id, Name FROM SomeTable__c";
force.query(strQuery, new com.salesforce.AsyncResponder(queryHandler, faultHandler));


..


private function queryHandlerSomeTable(result:QueryResult):void {
    if (result != null && result.records != null && result.records.length > 0) {
        for each (var item:SObject in result.records) {
            trace(item.Id);
            trace(item.Name);
        }
    }
    if (!result.done) {
        force.queryMore(result.queryLocator, 
                        new com.salesforce.AsyncResponder(queryHandlerSomeTable,
                                                          faultHandler));
    }
}



単純なfetchなら話は簡単でSOQLとSQLもまったく同じになります。問題はリレーションを使う場合です。force.comはオブジェクト型なので  Account.Name って書くだけで取引先名を引っ張ってこれますが(WebObjectsもそうだったなぁと遠い目)、mySQLはJoinで表を結合してAccount.Name には適当なエイリアス名を付けて参照する必要があります。このへん需要があれば詳しく書きますのでコメントください(ない、というオチが寂しい)


■Update/Insert

需要があれば書きます。


■共通の落とし穴■

fetchした結果はどっちもObject型みたいなもんに入って返って来ます。で、どっちもSQL/SOQLのattribute名とObjectから引っ張り出す時のkeyが間違っていると、fetchしたのにnullだったのか、SELECT文に書き忘れてnullだったのか、すぐにはわかりません。大文字と小文字を間違えてもダメです。SELECT文に書いた通りのkeyと完全に一致しないとダメです。Objectにkeyがあるかどうかを確認して、あるはずのkeyがなかったらエラーを出す、というような処理をはさみましょう。

まぁね…当たり前のことなんだけどね…。


■Force.comでのはまりどころ■

Flashとは違ってAIRで使う場合はデフォルトで同期がONになっています。ので、Fetch後に自動的にForce.com APIに対して問い合わせをします。しかし、相手はForce.com、頻繁に問い合わせするもんであっという間に1日のアクセス制限回数を超えてしまいます。ログイン前にでも以下の行を実行してキャッシュ切ってください。

force.doCache = false;


■asSQLの落とし穴■

update文でprimary keyの値を指定しますが…その値の型が間違っていた場合には、「success側のコールバック関数にfailが帰ってくる」という何が何だかわからない現象が起こります。これ気づくのに2時間ぐらいかかりました…だってねぇ…まさかねぇ…。

2012年3月12日月曜日

ご無沙汰しております

サラリーマンが忙しくて、ぜんぜん手が付けられませんでした。

とりあえず「SalesforceエンジニアのためのFlash入門」という需要があるんだか無いんだかまったくわからない連載をスタートさせようと思います。

どうぞよろしくお願いします。

2012年1月31日火曜日

Desktopを見るのが怖い…

いえね、昨日終業間際にDataLoaderを使って急ぎのインポート作業をやったんですけど、なかなかうまくいかなくてですね。

対象オブジェクトは3つ。何だかんだで20回ぐらいリトライしてようやくうまく行ったのです。で、そのままPCをシャットダウンしまして。

Desktopにアイコンが100個ぐらい並んでいるんだろうなー…やだなー…。

--

ところで、開発サンドボックスってレポートは移行してくれないんでしたっけ。昨日それで30分くらい右往左往してました。Force.com IDEでDeploymentすると「Success」で終わるのにフォルダに現れてくれない。foldersも一緒にデプロイしてもダメ。

本筋と関係ないので諦めましたが…。

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にしてください。

Batch Apex / Mailでハマった件

香港にて
お疲れ様です。

Batch Apexに限らないんだけど…arrayに入れたSingleMailMessageをまとめてどーんと送る時、その中に1通でも不達アドレスが含まれていると一通も送られないでエラーになりますね。

昨日はそれでハマりました。

Contactに関連付けたemailアドレスにメールを送って、それが正常に配信されないとそのアドレスには「確認しろよコラ」ってフラグが立ちます。その状態で同じアドレスにメールを送ろうとすると送信前にエラーになる。まぁそれは当たり前。問題は、不達アドレスだと検出されるタイミングが前回送信から数十分〜数時間かかるってところで、いつ判定されるかわかんない。なので大量に送信してたりすると、エラーがたまたま次回の送信Batchにひっかかってコケてました。

報告をするのにエラーの経緯を再現しなきゃいけないんだけど、そんな神業なタイミングをどーしろとw

それにしても、疲れてるとレアケースの推測がダメだわ。

今日は、送信前にそのContact / emailアドレスが不達だと判断する方法を探さなければ…。


2012-01-29追記:
EmailBouncedDate / EmailBouncedReasonがnullじゃなかったら不達ですね…。