2013年12月28日土曜日
iOSアプリ申請時に "This bundle is invalid. Apps that include an armv7s architecture are required to include an armv7 architecture" エラーが発生した時の対処法
2013年10月25日金曜日
Winter '14でのListView直接表示(Force.com)
タイトルの件ですが、Webタブに直接ViewのURLを指定して、
オブジェクトのランディングページをすっ飛ばしたい!
という要望を客先から聞いた時に isdtp=vwなどのURLパラメータを設定して
実現していた方は多いかと思います。
Winter'14から、上記方法では実現できなくなっていました。
デバッグしてみると、どうやらシームレスなリンクをするためのsrcUpメソッドが
iframe内で使えなくなっていることが直接の原因のようです。
(クリックインジェクション対策のせいかな?)
なので試行錯誤した結果、
VFページで
<apex:page action="{!URLFOR('ViewのURL')}" />
の内容でページを作成し、
VFタブを作成して設定すれば実現できました。
実はこれ、AppExchangeで配布されていたパッケージで実装されていたやり方なんですが、
目から鱗でしたね。
ええ。
その前日私はsrcUpを全てhrefリンクに変更するjavascriptを書きましたから(
上記方法でも一応は動きます。
が、面倒だしレンダリング仕様変更されたら一発アウトなのでやらない方がいいです。
というわけでちょこっとしたTipsでした。ではでは。
2013年10月19日土曜日
2013年10月17日木曜日
Rubyの文字列リテラルのUnicodeエスケープがうまくいかない時
Rubyの文字列リテラルはバックスラッシュ記法を用いてUnicode文字をコードポイントから表示することが出来ます。
(\uXXXXの形式)
>> puts "\u3042"
>> あ
しかし、コードポイントが5桁の場合、この書き方だとうまくエスケープされません。
(前半4桁と最後の1桁の2文字扱いになる)
>> ⃩5
この場合、以下の様にコードポイント部分を{}で囲むと期待通りにエスケープされます。
(\u{XXXX}の形式)
>> puts "\u{20e95}"
>> 𠺕
また、この形式ならば、スペースで区切ることで複数コードを一度にエスケープできます
>> puts "\u{20e95 3042}"
2013年10月8日火曜日
Xcode5でQuickHelpを書く
メソッド
書き方は表示したいメソッドの上部へ記述に従って書くだけでOK。例えば以下のように。/*! 社員の出社状況を設定メソッドを呼び出している場所で、三点タップしてあげると以下のように表示される(これは公式メソッドのQuickHelp表示方法)。
* \param employeeNumber 社員番号
* \param state 出社状況。YESなら出社で、NOならズル休み
* \returns 出社状況がDBに保存されたかを返す
*/
- (BOOL)setEmployeeWork:(NSInteger)employeeNumber withState:(BOOL)state
{
// 略
}
メソッド上にカーソルが存在する際、Xcodeのプロパティに以下のように表示されもします。
クラス
メソッドと同じようにクラスに対してもQuick Help表示できます。例えば以下のように。/*! ViewControllerViewControllerを三点タップすると以下のように表示されます。
* 存在価値のないクラス
*/
@interface ViewController : UIViewController
ちなみにQuick Helpを追加しなかった場合、以下のように継承元クラスのQuick Helpが表示されます。
2013年9月19日木曜日
iOS6からiOS7への対応
①アイコンの追加対応
iPhoneで1種類、iPadで2種類増加されました。iPhoneが1種類しか必要ないのは対応バージョンに非Retinaが無いためです。iPhone(120x120) ・Icon-60@2x.png iPad(76x76/152x152) ・Icon-76.png ・Icon-76@2x.png
②storyboardで作成した箇所のレイアウトが崩れる対応方法
Xcode4.6以前で開発していたプロジェクトをXcode5で起動し、初めてstoryboardを開いた時にstoryboardで作成した全レイアウトを自動調整してくれる。もしくは警告にそれっぽいメッセージがあるのでクリックすると自動修正されます。それでも未だグチャグチャな場合は他に原因があり。③UINavigationBarとStatusBarをUIViewに上被せで表示させたくない場合の対応方法
以下はUIViewControllerクラス等を継承したクラス上で使う想定のコード。もしTabBarだけは元の状態にしたいなら UIRectEdgeBottom を使う。self.edgesForExtendedLayout = UIRectEdgeNone;
④StatusBarとUINavigationBar上の文字とが被る
StatusBarの上にUINavigationBarが被さる事が原因だが③の方法で解決しない。発生する原因はUINavigationController上にUINavigationBarが追加されていないからUIViewController側がUINavigationBarを一つのControllerと見なして自動調整してくれないからなので、対応方法は以下のようにUINavigationController側でStatusBarとTopBarを使うよう定義すれば良い。⑤UIAlertViewがaddSubView出来なくなった問題への対応方法
TSAlertViewなどのUIViewを継承したカスタムAlertViewで代用。クラス名を置き換えるだけで対応出来るが、ダイアログの見た目はiOS6以前のものとなる。もしくはUIAlertView風に見せるのではなくUIViewControllerをモーダル表示する。https://github.com/mindbrix/TSAlertView
⑥UI部品の背景色が変更されない問題への対応方法
色設定の仕様が以下のように変わりました。今まで背景色を変更するのに使っていたメソッドが文字色変更用となり、背景色を変えるメソッドが新たに追加されています。// UI部品の文字色変更 setTintColor // UI部品の背景色変更 setBackgroundColor以下は具体的な背景色を変更する例。UISearchBarなどの特殊なUIに関してはメソッド名が違う点と色濃く表示される点に注意が必要、少し薄くするのがベターかもしれません。
UIColor color = [UIColor redColor]; // before [self.navigationController.navigationBar setTintColor:color]; [self.navigationController.toolbar setTintColor:color]; [searchBar setTintColor:color]; // after1 [self.navigationController.navigationBar setBackgroundColor:color]; [self.navigationController.toolbar setBackgroundColor:color]; [searchBar setBarTintColor:color]; // after2(差分だけ) [searchBar setBarTintColor:[color colorWithAlphaComponent:0.2f]];
⑦UI部品の一括色変更する対応方法
Window#対象メソッド で変更可能です。ただし、Window#setBackgroundColor で変更されるUIはUINavigationBarのみっぽく、UIToolBarなどは変更できませんでした。iOS7からデフォルト色が白から青に変更されているため注意が必要です。// AppDelegateクラス上 UIColor color = [UIColor redColor]; [self.window setTintColor:color]; [self.window setBackgroundColor:color];
⑧ホーム上のアプリ名の省略されない最大文字数変更
iOS7からフォントが変更されたのに伴い、ホーム上のアプリ名の文字サイズが若干変わったようです。今までは半角13文字まで省略されずに表示されていましたが、iOS7では半角12文字までに変わっていました。iOS6:半角MAX13文字 :全角MAX6文字
iOS7:半角MAX12文字 :全角MAX6文字
余談
この対応を入れたアプリを一週間以上前に申請したのですが未だにIn Reviewにすらステータスが変わらないので、今対応して申請してもしばらく待たされそうです。2013年8月29日木曜日
2013年8月5日月曜日
LeapMotion と openFrameworks で シューティング macアプリ
前回(Three.js)と前々回(box2dweb)につづいてLeapMotionネタです。
今回はmacアプリ。つくるのは前回みたいなシューティングゲームっぽいもの。
openFrameworksを使って
そこにLeapMotionを繋いでみます。
3次元に表示にするのでopenFrameworksアドオンのofxBt を使います。
そして初めてのC++。
2013年8月2日金曜日
LeapMotionとThree.jsでブラウザシューティングゲーム
先日の記事(Box2dWeb)に引き続きLeapMotionネタです。
シューティングゲームを作ってみます。
webGLのAPIを使いこなすことなど不可能です。
なので Three.js を使います。
Three.js はWebGLを使いやすくしてくれるライブラリで、初めて使いましたがすごーく使いやすいです。
2013年7月31日水曜日
LeapMotion と box2dweb でブラウザアプリ
先日うちの会社にもやってきました。LeapMotion
leapjs (http://js.leapmotion.com/) を読み込むことでブラウザJSでも使えます。
サンプルもいくつか出てます。↓
http://js.leapmotion.com/examples
ということで、js物理演算ライブラリのbox2dWeb に reap motion を繋いでみます。
指二本で動かします。
2013年7月20日土曜日
cocos2dx JavaScript Bindings の websocket
cocos2dx に xhr と websocketが実装されました。
cocos2d-x ver 2.1.4 が神アップデートすぎる件について
javascriptでopenglのパフォーマンスが得られるのは素敵なのに
通信ができないんじゃ使えないじゃん。
って思ってましたが、実装されちゃったので早速使ってみます。
twitterのstreaming api を流してみます。
こんな感じ↓
2013年7月16日火曜日
作るものの妥当性
正解ではなく妥当。
ふわっとしてていい言葉ですね。
僕らが作るもの(アプリとかwebサービス)にはだいたい二つの妥当性があります。
一つは経済のレイヤーにある妥当性。
簡単にいうと仕様通りに動くかどうか。
妥当でなければお金がもらえません。
こちらはお客さんとともに詰めていくもので、いろんなトレードオフの上に成り立ちます。
職能別の作業単位(責任)に明確に分けて考えれるものです。
もう一つは質(クオリティ?)のレイヤーにある妥当性。
これは自分らが作ったものとして世に出していいのかという判断。
経済レイヤーの妥当性とはあまり関係がありません。
自分らと作るものとの関係です。
主に全体としての納まりという所なので
コンテンツ、挙動、デザイン、コンセプト等々をまるっと考えて仕上げていく必要があります。
経済レイヤーの妥当性と関係がないとはいえ質のレイヤーにある妥当性をちゃんとしようとすると
やはり時間やお金(工数とよばれるもの)はかかります。なので僕らはここで戦いますが、
それだと食ってけない論が正論すぎて、反論できません。
そんな日々に慣れすぎると質のレイヤーの妥当性を忘れてしまいます。
2013年5月31日金曜日
iphoneの課金処理を見通しよくする
objective-cには無名クラスが無い(たぶん)。
なのにだいたいインタフェースがオブザーバー。
その都度処理かえるのがめんどい。
ということでBlocksインタフェースをつけちゃいます。
今日はStoreKit。
目標
課金処理の見通しよくする
使う側をこんな感じに
課金処理で結局何がしたいかというと、
・課金をリクエストして成功したか失敗したか。
・リストアをリクエストして成功したか失敗したか
controller.m
// 購入処理 SLSK* slsk = [SLSK getInstance]; slsk.onFail = ^(NSError* error){ NSLog(@"%@", error.debugDescription); }; slsk.onPurchaseSuccess = ^(NSString* productIdentifier){ NSLog(@"%@ 購入完了", productIdentifier); }; [slsk puchase:@"com.subakolab.tyarintyariiiiiiin" /*productIdentifier*/];
// リストア SLSK* slsk = [SLSK getInstance]; slsk.onFail = ^(NSError* error){ NSLog(@"%@", error.debugDescription); }; // リストア対象のアドオンの数だけ呼ばれる slsk.onRestoreSuccess = ^(NSString* productIdentifier){ NSLog(@"リストアアドオン:%@", productIdentifier); }; // リストアが全部終わったら呼ばれる slsk.onRestoreComplete = ^(){ NSLog(@"リストア完了!"); };
2013年5月29日水曜日
tail -f をブラウザで表示
tail -f /var/log/httpd/access_log tail -f /var/log/httpd/error_log
まーよく使いますね。
ディレクターとかお客さん(プログラムわかりませんの人)とかでもデバッグ中にログ流しながらできたら、デバッグしてますっぽい雰囲気出て楽しいんじゃないかと思ったけど、
sshつないでもらうの怖いしなー。
っていうことでブラウザにログを流してみましょう。
実際やるときはパーミッションとか認証とかちゃんとがんばってください。
データソースの抽象化
はじめまして、先週からスバコラボでお世話になっています。
好きなものはお酒、嫌いなものはプログラミングです。
手があいて暇なので
データソースの抽象化について書いてみます。
よくあるパターン
webAPIからデータを拾って表示するネイティブアプリ。
フォーマットもURLも決まってなくてモックが作れない
結合のときにやたらばたばたする。
APIがミスってるのかアプリがミスってるのか分かりにくい。
デザイン確認したいだけなのにAPIがバグっててアプリが落ちる
よくありますね。
このあたりをなんとかするために
モデルからデータソースを抽象化してみます。
目標
データソースの実装に引きずられないように
今回のサンプル
記事(Article)一覧をデータソースから読み込んで表示する
2013年5月23日木曜日
railsでの簡易遅延実行
お久しぶりです ヾ(o・ω・)ノ
最近時間がないせいか記事がなくて寂しいので書いてみようと思います。
また、iOSネタしかなかったので、たまにはrailsネタで。
以下のソースコードで遅延実行が実装できます。
# Gemfile gem "rack_after_reply"
# app/controllers/hogehoges_controller.rb def hogemethod env["rack_after_reply.callbacks"] << lambda { # 時間のかかる処理 } # 202 Accepted を返す format.html { render status: :accepted } end
これだけ。
いやー、簡単ですねー。
仕組み的には代表的な Rack サーバー(Mongrel, Passenger, Thin, Unicorn, WEBrick )が各リクエストを処理するメソッドをフックして、コールバックを実行しているとのこと。
2013年5月20日月曜日
新しい仲間が増えました
スバコラボに新しい仲間が増えました。
お金大好きでプログラミング嫌いなK君。
まあ、うちの社員は一人除いて全員K君なんですけどね。
そろそろ、部屋が狭くなって来ましたがギリギリまで
このアパートで頑張りたいと思います。
それではごきげんよう。。
2013年2月26日火曜日
2013年2月22日金曜日
OSのバージョンによるUIScrollViewの動きの違い
pagingEnabled=YES, bounces=YESのスクロールビューを使った時、
iOSの5と6でスクロールの動きが違ったので以下に内容を記載します。
例えば以下のようなコードを書いた場合。
scrollView.contentSize
= CGSizeMake(pageViewSize.width*maxCol, pageViewSize.height*maxRow);
この場合pageViewSizeのサイズ*グリッド数分の領域がcontentSizeとしてセットされます。
この時、pageViewSize.widthが1024、maxColが2だとすると
scrollViewのcontentSize.widthは2048になります。
この状態で、scrollViewのcontentOffset0,0から右フリックすると、
iOS5の場合は、1024を超えてoffsetが増加していきます、
(つまり、contentSizeを超えた領域までスクロールが到達してしまう。)
対策としては、scrollViewDidEndDecelerating内で位置を補正するコードを書くか
bounces=NOにして、バウンド処理を切れば、iOS5でも正常な位置でストップするようになります。
2013年1月23日水曜日
2つのModalViewを切り替えて表示する方法
※iOS5以上での方法となります。
storyboard
まずstoryboardで起動元画面を1画面、ModalView用の2画面作成します。左から以下の名前で進めていきます。
- ViewController
- ModalView1Controller
- ModalView2Controller
ModalView1Controller
1つ目のModalViewを実装していきます。以下は ModalView1Controller.h
@protocol ModalView1ControllerDelegate - (void)switchModalViewController:(UIViewController *)controller; @end @interface ModalView1Controller : UIViewController { id<ModalView1ControllerDelegate> myDelegate; } @property (nonatomic, retain) id myDelegate; - (IBAction)showModalView2Controller:(id)sender; // storyboardに配置しているボタンのイベント @end
// 遷移するトリガー。ここではボタンクリックにしています - (IBAction)showModalView2Controller:(id)sender { UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard_iPhone" bundle:nil]; // MainStoryboard_iPhone.storyboard UINavigationController *nc = [storyboard instantiateViewControllerWithIdentifier:@"Modal2ViewController"]; // StoryboardIDを指定 [myDelegate switchModalViewController:nc]; }ここではDelegateを使って、遷移元に次に表示したいModalViewのControllerを渡している点がポイントです。
ViewController
次に1つ目の画面であるModalView起動画面を実装します。以下は ViewController.m
// 遷移直前に呼ばれる - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { ModalViewController *controller = segue.destinationViewController; controller.myDelegate = self; // 上記はViewControllerに対して行う処理。Navigationとかは以下みたいにする // UINavigationController *navigationController = segue.destinationViewController; // MangaPageViewController *controller = (id)[[navigationController viewControllers] objectAtIndex:0]; } #pragma mark - ModalView1ControllerDelegate - (void)switchModalViewController:(UIViewController *)controller { // 遷移先のModalViewを閉じて、次に表示させたいModalViewを起動 [self dismissViewControllerAnimated:YES completion:^{ [self presentViewController:controller animated:YES completion:NULL]; }]; }ポイント2つ。
- 遷移する時にModalView1Controllerで実装してるmyDelegateにselfを設定しておく。
- delegateメソッドが呼ばれたら表示中のModalView1Controllerを閉じ、閉じる処理が完了したらModalView2Controllerを起動させる。
完成
実装は終わりましたので確認してみてください。2013年1月14日月曜日
iOS6以上でのstoryboard上のローカライズ対応
すっかりブログ書くことを忘れてたので初めての会社ブログへの投稿になります。
iOS6からstoryboard上のローカライズ対応が楽になりました!楽になった方法を書こうと思いますが、楽になったのは設定時であって前準備は非常にメンドウです。くじけぬ心を装備して臨みましょう。
Step1. プロジェクト作成
まずはXcodeでプロジェクトを作成してください。今回はiPhone/iPadのstoryboardを追加した状態で解説していきます。
|
Step2. Localizable.strings作成
Finderから「プロジェクト/en.lproj」ディレクトリに "Localizable.strings" ファイルを作成します。今回の初期設定時に巻き込んで作ってしまうと楽なので含めている為、今回このファイルは使いません。不要ならこのStepは飛ばしてください。
コード上で以下のように記述する事で利用します。
NSLocalizedString(@"kye", @"comment");
Step3. Base.lproj作成
Xcodeで「Project > info> Localizations > + > Other > Base(Base)」を選択。
|
ローカライズ対象のファイルを選べというアナウンスがあるので、全てチェックが付いた状態で「Finish」を押します。
結果、Baseとenはこんな感じになります。
|
Step4. *.storyboard用の*.stringsファイル作成
ターミナルから「プロジェクト/Base.lproj」で以下のibtoolコマンドを実行します。それぞれstoryboardに対応したstringファイルなので、そのディレクトリにあるstoryboard名が異なれば内容変更して実施ください。ibtool --export-strings-file MainStoryboard_iPhone.strings MainStoryboard_iPhone.storyboard
ibtool --export-strings-file MainStoryboard_iPad.strings MainStoryboard_iPad.storyboard
こんな感じに*.storyboardに対し、*.stringファイルが増えていればOK。 |
Step5. *.stringsファイル移動
Base.lprojに作成した.*stringsファイルを、en.lprojディレクトリにFinder(実際のファイルをって事)で移動させます。これでBase.lprojディレクトリに2ファイル、en.lprojディレクトリに4ファイルです。
Step6. Xcodeに今まで作成したファイルを追加
追加したLocalizable.stringsとstoryboardの*.stringファイルをXcode上に追加します。Xcodeから「メニュー > Add Files to "プロジェクト名"」から"Base.lproj"と"en.lproj"を選択します。 |
Xcode上で*.storyboardとInfoPlist.stringsが重複して邪魔なので消します。 |
Step7. 対応言語の追加
英語以外の言語を追加していきます。今回は"Japanese(jp)"を選びます。 |
まローカライズ対象のファイルを選べというアナウンスがあるので、 *.storyboard以外の全てにチェックを付けた状態で「Finish」を押します。 |
これで前準備は終わりになります。慣れれば簡単なのかな?いあそんなことは...
Step8. storyboard上でUI作成
iPhoneのstoryboardを対応してみましょう。"MainStoryboard_iPhone.storyboard" を開いて適当にUI作成してください。今回は以下のように作成してみました。 |
Step9. storyboardに表示するテキストをローカライズ対応
"MainStoryboard_iPhone.strings"ファイルの英語or日本語を開いて以下のようにkey-valueを設定していきます。"key" = "value";ここで重要なのはkeyの方です。keyは"MainStoryboard_iPhone.storyboard" を開いて、文字を表示させる対象の部品を選択し、storyboardの右Viewの左から3つ目にあるタブにある「Object ID」と値を設定したいプロパティ名になります。
もうひとつ大事なポイントとして、対象のプロパティには何かしらの文字を設定しておいてください。未設定だとkeyに対応したvalueが設定されません。
例えばUILabelの場合、私が作成したstoryboard上ではObject-IDが "udb-le-F0F" でした。これに表示させたい対象のプロパティ名 "title" を組み合わせた "udb-le-F0F.title" がkeyとなります。"MainStoryboard_iPhone.strings" 上には以下のように書きます。
"udb-le-F0F.title" = "Localize"; // 英語ファイルなお、今回iPhoneだけstringファイルを弄りましたが、このままではiPad側のstringファイルに何も書かれていない為、エラーになってしまいます。たとえ未使用でも*.stringファイルには何か書いておく必要があるのでご注意を。
"udb-le-F0F.title" = "ローカライズ"; // 日本語ファイル
storyboard上に文字を挿入したい時はこのStepを毎回行う必要があります。
Step10. ローカライズされた事を確認
これでローカライズ対応は終わりました。言語表示が"英語"と"日本語"で検証してみてください。切替方法は「Settingsアプリ > General > International > Language」となります。
もしうまく表示されない時はcleanするなり、アプリを一度削除する必要があります。
備考. 適当に試してみた
MainStoryboard_iPhone.strings(en.lproj)
/* UITabBarItem。Object-IDはUINavigationBar自体ではなく、Title部分のUIBarButtonItemな事に注意 */
"QxD-1d-LR4.title" = "Search";"hjG-GX-5Zj.title" = "Fav";
/* NavigationBar上のタイトル。Object-IDはUINavigationBar自体ではなく、Title部分のUIBarButtonItemな事に注意 */
"udb-le-F0F.title" = "Localize";
/* UIBarButtonItem */
"HHM-r4-1XD.title" = "Push";
/* UILabel */
"3b5-Va-UMR.text" = "subakolab Inc.";
/* UITextField */
"beM-F3-IQy.placeholder" = "hogehoge";"VKy-Ty-8Nf.text" = "input";
/* UIButton */
"Lrt-NR-GvK.normalTitle" = "tararara";
MainStoryboard_iPhone.strings(ja.lproj)
/* UITabBarItem */
"QxD-1d-LR4.title" = "検索";"hjG-GX-5Zj.title" = "お気に入り";
/* NavigationBar上のタイトル */
"udb-le-F0F.title" = "ローカライズ";
/* UIBarButtonItem */
"HHM-r4-1XD.title" = "押して";
/* UILabel */
"3b5-Va-UMR.text" = "株式会社スバコラボ";
/* UITextField */
"beM-F3-IQy.placeholder" = "ほげほげ";"VKy-Ty-8Nf.text" = "入力";
/* UIButton */
"Lrt-NR-GvK.normalTitle" = "たららら";
余談
ブログに書くのが途中で面倒くさくなって投げそうになったのをグッと我慢して書いたのでゼヒゼヒお試しください。何が面倒臭かったかと言うと今現在Bloggerのデザイン変更権限がアカウントに付与されてないせいで、ソースコードを綺麗にハイライトしてくれるjsを組み込めなかったせいで自分でハイライトさせた事ですね。そのままだと見難いし、でも面倒くさいしの間でたゆたってました。