UIWebViewをコードでズームする方法の覚え書き

iOSプログラミングの話です。

アプリ内にWebブラウザコンポーネントであるUIWebViewを埋め込んで簡易的にWebページを扱えるようにする必要があったんですが、その表示倍率を直接制御するメソッドやプロパティがありませんでした。海外の掲示板も含めて結構質問は出てたんですが、有用な回答は得られず。

まず散見されたのはUIScrollViewの上にUIWebViewを置いて、UIScrollView側でピンチやスクロールを制御すればいいんじゃね?というアイデア。実際にやってみたんですが、以下の問題点がありました。

  • UIIWebViewの標準操作であるダブルタップでブロック最適化ズーム(?)動作が使えなくなる
  • ズームの品質が低い(文字がボケる)

そして何より、よくよくAPIガイドを読んだら「UIWebViewとUITableViewをUIScrollViewの上に置くのは予期せぬ動作を引き起こす可能性があるので推奨しない」と書いてあった。禁止ではないのでAppStoreの審査でリジェクトされるといほどではないかも知れないけれど、将来的なAPIの仕様変更でおかしなことにならないとも限らない。

で、悩んだ末に辿り着いた答えは、stringByEvaluatingJavaScriptFromStringメソッドを使ってWebコンテンツを書き換える方法。

まず単純な例。

[webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat: @"window.scrollTo(0, 100);"]];

これを実行すると、Webコンテンツ上で「window.scrollTo(0,100);」というJavaScriptを実行したことになります。つまり画面が下に100ピクセル分スクロールします。

これを応用して、iOSのブラウザに対するズーム定義をmetaタグで追加してやる、ということをしてやるワケです。metaタグの仕様についてはAppleのドキュメントを参照するか、「meta viewport」などでググって下さい。

今回の閲覧対象ページはこのmetaタグ自体が存在しなかったので、タグ自体を作成してheadタグの中、titleタグの前に挿入しています。

[webView stringByEvaluatingJavaScriptFromString:@"var bodyNode = document.getElementsByTagName(‘head’).item(0);"  
"var titleNode = document.getElementsByTagName(‘title’).item(0);"
"var newNode = document.createElement(‘meta’);"
"newNode.name = ‘viewport’;"
"newNode.content = ‘width = 1024, initial-scale = 1.2, minimum-scale = 0.3, maximum-scale = 1.2’;"
"bodyNode.insertBefore(newNode, titleNode);"];

@””の文字オブジェクトは;で切らない限り改行入れて列挙できるので、見やすさの為にそうしています。

1行目でbodyNodeという変数にheadタグの位置を取得。

2行目でtitleNodeという変数にtitleタグの位置を取得。

3行目でnewNodeという変数にmetaタグを作成。

4行目でそれに「name=’Viewport’」に相当する記述を追加。

5行目に更に「content = ‘width = 1024, initial-scale = 1.2, minimum-scale = 0.3, maximum-scale = 1.2’;" 」を追加。数値は適宜状況にあわせて調整を。ちなみに=の前後にスペースがないとダメとどっかで読んだのでそうしてます。

6行目で、bodyNode(=headタグ)内のtitleNode(=titleタグ)の直前にnewNode(=metaタグ)を挿入して完成です。

 

最初から「<meta name=’viewport’…>」が書かれているページに対してはcontentだけを書き換えるような処理をしないといけないので、汎用的なWebブラウザとして使うなら分岐処理も入ったもう少し複雑なJavaScriptが必要でしょうが、今回は対象サイトが固定のアプリなのでこれだけで済みました。

参考になれば幸いです。

[宣伝] iOSアプリ「独りブレスト!発想会議」リリースされました

3月からプログラミングを担当していたU’eyes Design製のiOS(iPhone)アプリ「独りブレスト!発想会議」がリリースされました。5月の某研究会でβ版を初お披露目した時に「(Apple絡みだけに)泳げる頃までには(ってこのネタわかるのオサーン)」なんて言ってましたがなんとか実現して良かったです。

ちなみに審査にかかった時間ですが、Appleからのメール着信時刻で言うと、

  • 11/06/20 17:05  Waiting for Review (審査待ち)
  • 11/06/22 22:05  In Review (審査中)
  • 11/06/23 12:44  Processing for App Store (AppStore向けに処理中)
  • 11/06/23 12:51  Ready for Sale (販売準備完了)

という感じで、三日程で通ってしまいました。しかも一発合格。初めてにしては上出来じゃないすか?

AppStoreの審査は、例えばテーブルビュ-(リスト画面)で下位階層に遷移してから上位階層に戻った時に、最初のフォーカスがじわっと消える効果が入ってないとリジェクトされる、とか細かいガイドライン準拠もチェックされると聞いていたので、あれこれ気をつけつつもかなり不安だったんですが、ホント一安心です。

■アプリ紹介

せっかくなので公開したアプリの紹介も。

端的にいうと、商品企画などで新商品、新サービスの企画アイデアを生み出す為の支援ツールで、新しい発想を採り入れたいテーマ(下の写真の例では「扇風機」)を設定すると、1枚目の写真のように発想のトリガとなるキーワードが付箋紙として表示されます(写真1枚目)。このキーワードが全部で117種類あって、スワイプで次々めくったり、下部の「101」と出ている吹き出しをドラッグして好きなものを出したり、あるいは左下のシャッフルボタンでランダムに表示したりできます。

テーマに対して何か閃きをくれそうなキーワードに出会ったらタップして赤丸をつけます(写真2枚目)。「“自然の美しさを持つ”扇風機ねぇ…そうか!例えば花びら型とか?」なんて閃いたらミニ付箋にメモを書き込んでおくこともできます。

このアプリでは赤丸をつけることを「クリップ」と呼んでいて、トップ画面から「クリップリスト」を開いてテーマを選択すると赤丸をつけた付箋とそのメモ内容を一覧したり、メモの編集を行ったりすることもできます(写真3枚目)。またこのデータはExcel等で読み込みやすいCSV(カンマ区切りテキスト)形式にして、メールで送信したり、iTunesから取り出したりできます。CSV形式でクリップボードにコピーすることもできるので、Evernote等に貼り付けても良し、です。

 

mzl.eirkhwti.320x480-75mzl.qqnnybor.320x480-75mzl.gmguttdg.320x480-75

 

で、ここで使われている117の発想刺激ワードというのが、単に思いつきで書き殴ったものではなく、U’eyes Designのリサーチに基づいたものであることがこのアプリの価値となっています。簡単にいうと、「あなたが最近感動したものは?」というアンケート調査をして、その回答(感動シチュエーション)を分析して抽出された、いわば感動エッセンスとでも言うべきワード集なんです。これをU’eyes DesignではXB法(クロスビーと発音)としてチームで発想会議をする手法として導入しセミナー等を行ってきました。これをスマートフォン向けアプリとしてスピンアウトし、一人でも実践できるようにしたのがこの「独りブレスト!発想会議」というワケです。「独りなのにブレスト?会議?」というツッコミ待ちのネーミングが秀逸ですよね(σ(^^)の発案ではないので自画自賛ではない)。

商品企画に携わっていない人でも、家族や友人へのプレゼント選びのような「感動」させたい発想の支援に幅広く利用できると思います。お値段230円!プライベートでもご利用いただきやすいお手頃価格となっております。是非お試しあれ!

2011.07.14追記:

2011.07.12頃、ついにビジネス有料ランキングで1位を獲りました!ありがとうございます。

あとYouTubeに解説動画がアップされました。動いている様子をご覧いただけます!

 

独りブレスト!発想会議 - U'eyes Design Inc.

iOS開発修行中に参考になった本を紹介 (2)

以前のエントリから更に追加で買いまくったので紹介。今回ほぼボランティアなんだけど、投資だけはこんなにしてしまって大丈夫かw?

■木下誠「iOS開発におけるパターンによるオートマティズム」

今回一番役に立った本です。前回紹介した「たのしいCocoaプログラミング」の木下さんの本で、あれほど砕けたノリではないものの、iOS開発でお約束の定型ルーチンのお手本を示してくれています。特にデータの保存と読み込み周りはこの本のおかげで実装できたといっても過言はないです。


■Dave Mark「はじめてのiPhone3プログラミング」

独立の複数筋から激しくオススメされたので購入。Amazonのレビューで翻訳の質がイケてないという指摘があり、また世代的にも古いので最初は下の原著を買ったんですが、UITableView等の理解がおぼつかなくて少しでも負荷を下げようと結局購入。

誤訳も多いと指摘でしたが重版で直ってるっぽいからいいかと思って買ったのに、帰省中に豊橋で一番大きな書店の店頭在庫を買ったらまさかの初版で激しく落胆(帰宅してから気付いた)。これから買う人はお気を付け下さい。

というか改訂版出ないんですかねぇ。


■Dave mark「Beginning iPhone 4 Development: Exploring the iOS SDK」

上記の原著、改訂バージョンです。Kindle版を買いました。章毎にお題を掲げてサンプルアプリを実装していく形式で、なかなか実用的なお題で、ViewController周りなどは参考にしました。

(洋書では普通かも知れませんが)この人もノリは軽めです。


■安倍吉俊、カワサキタカシ「サルにもできる iPhone 同人誌の創り方」

画像ファイルを差し替えるだけで電子書籍アプリを作れるというウリの本です。今回作ったアプリは書籍ではないですがスワイプでページをめくるという部分は同じだったので、こちらの本のコードを大いに参考にさせていただきました。というかこのソースをベースに機能拡張をしていったので、完成形は似ても似つかないですが、ViewControllerのクラス名がいまだにsABViewerだったりしますw。本当にありがとうございました。

半分は安倍さんのイラスト集なのでファンでないと割高感あるかも(笑)。あと技術サイドの著者であるカワサキさんは掲示板も開設しておられるようです。ユーザ登録まではしましたが結局まだ書き込みはしてませんが。


■森巧尚「よくわかるiPhoneアプリ開発の教科書」

カラーで見やすいレイアウトと丁寧なコード解説ですごくとっつきやすい本でした。こちらもテーブル表示の章はずっとにらめっこして大いに助けになりました。

初めて読む入門書としてはオススメの一冊です。


■畑 圭輔「iOS4プログラミングブック」

こちらも推薦を受けて買いました。Ratinaディスプレイ周りを参考にしました。逆に非RatinaなiPhone3GSなどで1ピクセル幅の線を描画してもアンチエイリアスがかかってボケて2ピクセルになってしまうのを回避する方法などをこれで勉強しました。iOSの表示倍率の考え方についてとても詳しく書かれているので、これから更に機種が増えて互換性をとるのがややこしいことになった時にとても重宝すると思います。


■國居貴浩「iOSデバッグ&最適化技法 for iPad/iPhone」

開発後期段階になって効率化やメモリリーク対応の勉強のために買いました。Xcodeの一部である解析ツールの使い方などについて紹介しています。

ただσ(^^)のメモリ管理に対する理解が浅いせいか、ちと物足りない印象でした。Provosioning周りの説明なんかもあるんですが、そういうのはいらないのでもっとタイトルの内容をつきつめて欲しかった気がします。「実践編」みたいな続編を期待。


■Alasdair Allan「Learning iPhone Programming」

ProvisioningやAppStore申請周りについて詳しく知りたいなぁと思って物色していたところ、こちらが章を割いて解説してるっぽかったので買いました。オライリーですが日本語はまだ出てないっぽいです。Kindle版で買いました。

実際結構参考になりましたが、後でAppleが日本語PDFで結構詳しいドキュメントを配布しているのに気付き、もしかすると最初からそれだけで済んだかもという気もしています。これからの人はまず先にそちらを熟読してみて下さい。

全体としては普通にプログラミングの本ですが、目的の章以外は読んでません。その意味でもちょっと割高感。まぁ元の値段自体が安いからいいんですけど。

■高山恭介「iPhoneSDK開発のレシピ」

よくある、「○○をしたい」的な小さなテクニックがたくさん詰まった系の本です。UIAlertViewの中に入力欄を持たせたものが標準でなかったので、これを参考に実装しました(結局使わなかったけど)。あとメールにデータを添付して送信するという部分も参考にしたかな。ヒット率(あー、それしたいわと思う率)は結構高いレシピ本だと思います。


■D・H・スタインバーグ「iPadプログラミング (Smart Mobile Developer)」

これはつい最近の購入で、今回のアプリには直接役だってはないですが、iPad(iOS3.2)から実装されたジェスチャー認識機構(GestureRecognizer)についての詳しい説明が参考になりました。オリジナルのジェスチャーコマンドを実装する方法についても紹介されています。また、UIPopoverViewなどiPad独自のGUIパーツはiPhone系の本だとあまり触れられていないので、iPad専用アプリを作るのには重宝します。

GestureRecognizerはもう少し早く知っていれば、今回のアプリにも積極的に活用できたのになぁという印象です。今回のアプリではデバッグ段階で複数のボタンを同時にタップした時に両方反応してしまって思わぬ動作を引き起こす、という現象の抑止にかなり時間を割きました。たぶん、GestureRecognizerを使ってタップ判定を一元化しておけば簡単に抑制できたんじゃないかと予測。


■細谷日出海「iPhoneデジカメプログラミング」

これに至ってはまだ昨日買ったばかりで読んですらいませんが、バーコード読み取りとAmazonから商品情報をひっぱってくる辺りのサンプルが扱われていたので、今やりたいと思ってるアイデアに直接役立つだろうと思って押さえてみました。

バーコードに関しては標準APIではないですが簡単に利用できる外部ライブラリがあるみたいです。またAmazonからの商品情報取得は、Mac用に考えてるアプリで応用できるんじゃないかと。読むのが楽しみです。


 

とまぁ、買いも買ったり、前回分も含めればン万円ですね。申請が済んだ某アプリに対する報酬額が未だに通知されないのですが、元が取れなかったらどうしよう…。まぁ今後の為の投資だと思えばいいんですけどね。こういうのを全部自腹で買わなければならないのは自営業の辛いところです。

ですがまぁ、(震災で大変だったことを別にすれば)総じて楽しい三ヶ月でした。

iOS開発で苦労した点を振り返る

3月からずっとプログラミングを担当していたiOS向けアプリが本日ようやくAppStoreに申請完了しました。Xcode、Objective-Cはもとより、ポインタとかオブジェクト指向プログラミング自体が初めてで本当につまづきまくりでしたが、ホッと一息です。まぁ、まだ審査という大きな壁があるわけですが、とりあえず時間は少し余裕ができるのでこちらのブログもぼちぼち再開していきたいと。

さてまずは表題。PHP、VB.NETあたりはちょいちょいやってきた(だがOOP的なことはほとんどしたことがない)視点から。慣れてしまった今とはってはそれなりによくできてると思うし、何故当初そんなにつまづいたかも徐々に忘れつつあるのですが、なんとか思い出せる範囲で書き留めておこうと思います。同じようなところでつまづいてる人の参考になれば。あと今回教えてもらった人にも「何がわからんのかわからん」と言われたので、そんな指導する側の人にも初学者の陥りがちな(?)勘違いを知らしめる意味で、恥を晒しておきます。

・宣言ファイル.hと実装ファイル.m

初心者はまずここから躓きますw。新しいクラスhogeを作ると、hoge.h、hoge.m(そしてViewControllerの場合はさらに.xibも)というファイルができます。VB脳からするとなんぞこれ?ですよね。実際のところ宣言と実装という言葉でほとんど説明できてしまってるんですが、最初はとにかく情報量が多すぎるのでこれだけでもビビります。VB的に実際のコードを書くのが実装ファイル(.m)ですね。じゃぁ.hは何かというと、そのオブジェクトが内包しているプロパティオブジェクトやメソッドの一覧が記された設計仕様書という感じ。他のクラスから利用する場合にこの.hファイルをimportしといてやると、そのクラスがもっていないメソッドを呼ぼうとした時にXcodeがそいつはそんなメソッド知らんってよ?と警告してくれます。まぁ、実際には.m側を精査すれば同じ内容は得られるんでしょうし、むしろ.mではちゃんと実装してるのに.hに書いてないからエラーになるなんて本末転倒なこともあったりするんですが、作業面でもまず.hに「こんなメソッド作るぞ-」とかToDo的に書いておけば、未実装の分はやはり警告が出るので便利っちゃ便利です。

・Interface Builder

これも慣れてしまうとどうってことないんですが、Objective-C自体がよくわかってない状態ではハマりました。Interface Builder(以下IB)で配置したボタンなどのオブジェクトを、そっくりコードの上でも宣言して、それを紐づけてやらないといけない、というのはVBにはなかったので。しかもIBAction(GUI部品から操作イベントを受け取るメソッド)とIBOutlet(コードから部品に表示を反映させる先)の双方向を別々にとか。でその方法がCtrl+ドラッグだったりと、あんまし直感的じゃなかったり。なんでもインスペクタからするVB的感覚とだいぶ違いますね。勢い解説書でもひたすら手順を説明するに留まって、読んでる方はすごく「やらされ感」が募ります。D&D操作って静止画のみの書籍での解説とは相性悪いのもあるんでしょうかね。

ただ慣れたせいかもですが、途中で導入したXcode4になってから随分やりやすくなった気がします。前バージョンだとIBは独立アプリという感じで、コードを保存しないでウインドウだけ移っても反映されてない、とか色々不便でしたし。ちょっといじってみようという人には有料になっちゃいますが、これから入門するならXcode4オススメです(一気にDeveloper Programにお布施しちゃうぞー、って人はタダです)。

個人的理解度がいまだにあやしいのはMainWindows.xibの扱いですね。まぁ、各種テンプレートを使ってプロジェクトを作った場合はほとんど触ることなさそうですが。

・delegate

これは悩みました。ググればなんなのかはいくらでも記述があるんですが、どう嬉しいのか、どういう場面で使うべきかがいまいちピンとこない。当初、親ビューなどスコープの届かない別オブジェクト(例えば大元のAppDelegate.m)の中のプロパティに上手くアクセスすることができず、仕方ないのでメソッド自体をその別オブジェクト側に移してそこで処理する為のものだと思って利用してました。だって一番最初のクラスの名前についてるしw。グローバル変数的なプロパティとそれにアクセスするメソッドを全部集めるべきか、とかw。

だが先輩プログラマ(同級生だけど)にそうではないと教わりました(hogeAppDelegate内のプロパティにアクセスする簡単な方法も教わった)。標準のクラスとはちょっとだけ違う振る舞いをするオブジェクトが欲しい時に、次々にカスタムオブジェクトを作っていくと大変(.h/.mペアがどんどん増える)なので、それをまとめて1つの.h/.mで処理するって感じですね。特にUIButton等のGUIパーツをIB上で配置すると本来は.hや.mはいらない訳ですが、そこに1つだけ特殊なことするメソッドが欲しい、なんて時に、そのボタンのdelegate(代行)先を親ビューであるViewController.mにして、そこにメソッドを書く、なんてことをします。うん、今ならこれがないと大変だということがわかる。特にUITableViewはOS側から呼ばれるイベントハンドラが多い(総行数の問い合わせとか)ので、それを実際のデータをもってるオブジェクトに“転送”したりするのに使いまくりでした。うん、イベントハンドラの転送、と考えるとしっくり来る。

・ポインタ

十数年間もσ(^^)が各プラットフォームでネイティブアプリを書く障壁となってきたポインタは、Objective-Cでは思ってたほど意識する必要なかったみたいです。宣言する時に、オブジェクトかどうか見極めて*をつけるかどうか判断する位。INTやBOOLでは不要だけど、文字列(NSString)はオブジェクトだからつけないとダメとか。プロパティやメソッドの引数を宣言するところ以外では*つけなくてもいいので、普段はあんまり意識しなかったです。

ただ高速列挙という、ある配列内のオブジェクトを順に取り出して順に処理していく方法の中で、一次変数オブジェクト作ってそれを取り出して変更を加えた後、元変数に書き戻さないといけないと思ってましたが、実際には取り出してなくてポインタをコピーしてただけなので書き戻し操作は不要だった、なんてことがありしました。

あと開発後半でリーク対策をしようという段になって、ちゃんと理解してないとダメだなと思いました。変数の感覚でポンポン“代入”をしてると、Leakテストした時にビックリしますw。

でもまぁとりあえず始めるにあたっては他のC系言語ほど怖がらなくてもヨサゲ、ってことだけは言えます(って他のC系言語実際に挑戦すらしてないけど)。

・@propertyと@synthesize

この辺も訳わか
らないウチは、なんで同じ様な宣言をあちこちで何度もやらされるんだろう?と混乱しますね。.hファイルの中でプロパティを宣言した上で、同じファイルのすぐ下で@propertyで繰り返し宣言をし、さらに.mで@synthesizeですよ。これらは主にクラス外からプロパティにアクセスする時に必要なもので、@propertyはそのヘッダーファイルをimportした他クラスに対して、自分はこんな“プロパティ”を外部に公開してるよー、と知らしめる為で、クラス内部でしかアクセスしないならなくてもいい。また@synthesizeは.mファイル側で実際にset/getするメソッドを自動で“シンセサイズ”(生成)するためのもの。@synthesize hoge;とするだけなので超簡単ですが、これを使わずに自前でメソッドを作ってもいいので、やっぱりプログラマが任意で書かなきゃダメって訳です。似てるんだけどそれぞれ役割が違う。

 

とまぁこの辺がちょっと壁だったような気がします。というかまだ間違ってるかも知れないので、そこは皆さん追々ちゃんと調べて勉強していって下さい(^^;)。とりあえずこんな感じで理解したら少し前に進めた気がする、ってことで。

Appleの開発者登録手続きが清々しいまでにヒドい件

iOSプログラミングに慣れてきて当然実機で動かしてみたくなります。早速有償のiOS Developer Programに登録申請してみました。

がこのフローがヒドい。友人からの事前情報で、Apple IDに日本語が含まれているとアクティベーションにコケて、メールで修正依頼をしたりして長いこと待たされることがわかってたので、色々ググってみました。要約すると、

  • Apple IDの登録情報に2バイト文字があるとアクティベーションに失敗する
  • 逆にすべて英語だと日本のApple Storeでの決済手続きがエラーになる

もうこれだけでもヒドい話です。どうしてこんな簡単な問題が何年も放置されてるんでしょうね?

なんとか問い合わせ手続きしなくて済むようにと、先人達の記録を参考に、開発専用の新規Apple IDを取得してすべて英語で記入するところから始めてみました。開発者申請のページから新規にApple IDを登録するとこから始める選択肢があるのでそれを使います。メール認証をして登録完了。続けて有償ライセンスの購入に進むと、カートにライセンスが入った状態で日本のApple Store画面にリダイレクトされます。そのまま決済に進むと、名前や住所を日本語で入れ直すよう促されます。これで無事決済は完了。午前零時前後に手続きしたところ、数時間後の翌朝6時半くらいにアクティベーションコードがメールで届きました。

が、結局お約束のエラー!

新しくApple IDとった意味なし。愚痴をたれつつも、エラー画面内の「Contact Us」というリンクから行ける問い合わせフォームで連絡。こちらからアクションを起こさない限り向こうはなにもしてくれないそうなので。で、最短で手続きが進む様に、あらかじめネットで調べて必要事項(Apple Storeの注文履歴画面から、

  1. 『ご請求、ご連絡先』
  2. 注文番号 (W+数字8桁)

をコピペ。またメールにあったEnrollment IDも添えて送信したのが朝9時。返事が来たのが午後2時過ぎ(日本語)。あろうことか、上記の情報を知らせろと書いてきています。だからコピペしたでしょ?とメールに添付されたフォーム記入文面を見る。なんと、

2バイト文字が全て抜け落ちてます。

コピペした「We are unable to activate」というエラーメッセージ、住所の中の部屋番号と番地と郵便番号、注文番号、Enrollment IDという英数字のみの意味不明な送信文です。おそらくエラーメッセージから問い合わせ内容を類推して返信してきてるんでしょう。

日本語入れると全部抜かれて送られるフォームなんてナナメ上過ぎ。

これまた知人から「Appleは開発者に優しくない会社」と聞いてましたが、確かにその通りかも。あるいは非1バイト文字圏軽視しすぎ。

 

結論としては、「一発申請は不可能。あれこれ悩むより余裕もって申請して、さっさとエラー出してContact Usから連絡。RegionにJapanを選択し、上記エラーメッセージさえ貼り付けておけば用件は通る。日本語は書いても無駄。詳細はその後のメールへの返信で記入」ってとこですかね。もしかするとContact Usフォームに請求、連絡先情報を英語表記にして貼ればいいのかも知れませんが、たぶんApple Storeの表示とマッチしないとNG食らう気がします。