なるようになるかも

力は多くの場合、その人の思いを超えない。

今年入ってから読んだ本とか。

NFC Hacks

NFC Hacks ―プロが教えるテクニック & ツール

NFC Hacks ―プロが教えるテクニック & ツール

2015年になって、ようやくNFCについて真面目に学びました。

iBeaconは流行した頃に触ったんですけど、NFCは「どうせiOSで使えないし~」という理由でスルーしていたのです。

NFCとiBeaconを同じカテゴリに入れてるところからして間違いでした。全然別物ですね。

この本はおおまかに、

  • 物理レイヤ・・・動作原理について、電磁誘導がどうとか
  • 規格レイヤ・・・typeごとのメモリ構造やコマンドコード
  • アプリケーションレベル・・・AndroidWindowsにおけるコード例

という広いレイヤでNFCを扱っています。

ただ、この本を漫然と読んでも、書いてあることの意味を理解できないと思います。また、以下の点に注意が必要です。

  • ページ的に仕方ないですが、コードは割と基本的なことしか書いていないです。また、出版時期の関係上、Android 4.4のHost card emulationのような比較的新しいAPIには触れていません。
  • 標準規格寄りで書かれています。
    • 例えば、MIFARE Ultralightntには、それ自体の仕様と、同時にそこから派生したType2という仕様があります。この本は個別のNFC製品の仕様ではなく、NFC Forumが定めるtypeを基に広く解説しています。
    • メッセージの保存方法として、NDEFを重点的に解説しています。これはAndroidで規格を意識せずNFCタグを扱う上で非常に便利です、スマートポスターを作るなど簡単な用途としては十分です。本格的にNFCを採用したアプリケーションを開発するのには向かないように思います。

APIがあって、データの保持規格に共通仕様があるなら、簡単に読み書きできるんでしょ?」という甘い考えはあっさり崩壊しました。例えば交通系カードの履歴を読み込みたければFeliCa仕様書を読んでコマンドコードを調べて、バイナリと格闘し、タグと通信する必要があります。

タグを買って実際にコードを書いて、そのとき副読書としてこの本を読むと、非常に的確な解説だと唸らされます。

ハイパフォーマンス ブラウザネットワーキング

ハイパフォーマンス ブラウザネットワーキング ―ネットワークアプリケーションのためのパフォーマンス最適化

ハイパフォーマンス ブラウザネットワーキング ―ネットワークアプリケーションのためのパフォーマンス最適化

英語版は無料公開されています

ブラウザネットワーキングとあるように、どちらかというとJavaScriptでフロントエンド最前線にいたり、インフラ系エンジニアに向けた本なのですが、「HTTP/1.1の何が通信のボトルネックになっていて、HTTP/2にすることでどう早くなるのか」について学ぶ上でこれを超える本はないと思います。

もし「SPDYに対応した通信ライブラリを使えば、それで勝手に高速になるんじゃないの?」とか思っているなら、とっとと読んだ方がいいです。

モバイルネットワークの歴史、どのようにネットワークを利用することが電力的に効率的なのかなどの章も必読です。原著はアメリカで採用された3G、4G規格を前提に話をしていますが、日本語版は「日本ではどうだったのか?」という部分をフォローしているので(それだけに限らず全体的に訳注が非常に丁寧)、日本語版がお奨めです。

Web SocketやWebRTCの章は流し読みしましたごめんなさい。ネイティブ開発の片手間のJavaScriptでやるには流行り廃りが激しすぎです…。

APIデザインの極意

APIデザインの極意 Java/NetBeansアーキテクト探究ノート

APIデザインの極意 Java/NetBeansアーキテクト探究ノート

これは個人的な娯楽として読みました。

読み解くには知識と恐らく経験が必要で、しかも凄まじい密度があり、かなり人を選ぶ本だと思っています。少なくとも、私は後方互換性に厳密であるべきAPIを公開した経験がないので、正しく解釈できている自信がありません。

なので感想として言えることは、これほど面白い本が邦訳されてくれてありがたいです、ということくらいです。

挿絵のセンスはないと思います。

AndroidもiOSもC#で書けるようになればいいのに。

Xamarinはなんか生理的に受け付けないのでなしで。

しかし,実際に実装するにあたっても可読性のために同じようなところに改行を入れるとおもいます.

という記述が気になったので、実際に実装してみました。

Bookmarkの構造が分からないから、NSDatebookmarkedBOOLisHotentryを持つクラスだと仮定します。

- (Bookmark *)latestHotEntry:(NSArray *)bookmarks
{
    NSPredicate *latestHotEntry = [NSPredicate predicateWithFormat:@"SELF.isHotentry = YES AND SELF.bookmarked = SUBQUERY(%@, $b, $b.isHotentry = YES).@max.bookmarked", bookmarkes];
    return [[bookmarkes filteredArrayUsingPredicate:latestHotEntry] lastObject];
}

そんなに冗長な記述にならない気がします。

NSPredicateの公式ドキュメントの雑っぷりとか、@maxの存在なんてほとんど誰も覚えてないとかそういうのは考慮してないので、実用的に使えるかは微妙ですけど。

Swiftって実際にはNSObjectNSArrayの恩恵を受ける必要があるので、「純粋なSwift」そのものはいまのところ微妙だなーと思ってます。

あと、blocksはAppleによる「C言語」の拡張なので、blocksの可読性が悪いのを理由にObjective-CディスってSwift持ち上げてるのはなんか虚しい。しかも両方とも仕様作ったのはAppleですよ…。

参考資料

強制バージョンアップの話。

という記事を見かけたので。

このライブラリの実装の問題点

key description
type 基本的には強制バージョンアップを行うことを前提に解説していますが、SRGVersionUpdaterではキャンセルボタン付きの告知アラートを表示することも出来ます。強制アップデートの場合は"force" を任意でのアップデートの場合は"optional"を入力して下さい。

これ、設計ミスってません?

一度致命的なバグを出して"force"で通知したら、それ以降二度と"optional"は使えません。「必ず一定以上のバージョンを使って欲しいけど、最新版の通知もしたい」ようなユースケースに対応できないなら、"optional"の存在意義はない気がします。

あと、「評価が付くまで様子見ユーザー」層は毎回"optional"の通知を繰り返し見せられて離れます。開発者がいいと思ったアップデートが必ずしもユーザーに受け入れられるとは限らない(むしろ逆のケースのほうが多い)のです…。

もう一点指摘するなら、一度強制バージョンアップ対象になった端末は、その後通信する必要がありません。何度起動してもストアに飛ばされるだけなので。

条件を付けてレスポンスをキャッシュすることで、余計な通信負荷を減らすことができます。機内モードに入れるなどして、バージョンチェックを迂回する裏道もなくなります。ただし サーバーの設定が間違っていた 場合の救済策がなくなります。

解決すべき問題について

古いバージョンのアプリで特定の操作を行うと、データが破損しアプリの操作が不可能となるバグが発見された

この本質的な原因は、単なるテスト不足です。

強制的に最新のバージョンに上げてしまうと、新たなバージョンに致命的なバグがあったとき、全ユーザーに被害が拡大するだけです。

品質管理の問題に対して、「強制バージョンアップの運用で解決する」という方法論を取るのは、正直微妙な感じがします。

サーバーサイドとの通信部分で使う認証ロジックに問題があり、古いバージョンでの認証ロジックのままでは成り済ましが出来てしまう脆弱性が発見された

これも根本的なところではテスト不足なのですが、それに加えてアプリとの連携APIを作る場合は、

  • 利用不可(非推奨)バージョンであることを通知する
  • 利用非推奨APIとなったことを通知する
  • サービスの終了(移行)を通知する

というのを、設計段階で想定するべきだと考えています。

これはリクエスト時にバージョンを受け取って、何らかのレスポンスコードで判定を行えばいいだけなのでまったく複雑ではないです。

アプリとAPIの寿命は長いとは言えません。設計段階で死の概念を内包しなければならない、と考えています。

楽ではないJSONのデプロイ

「たった3行」で導入できますが、運用は大変です。

これまでの経験上、最新版のアプリを配信開始しiTunes Connectの状態がReady for Saleとなっていても実際にApp Storeに反映されるまでには1〜3時間程度の時間差がありました。

にもありますが、アプリをデプロイしても実際に反映されるまでのラグを考慮する必要があります。全てのユーザーが本当にダウンロード可能になったのか、定期的に確認する必要があります。

加えて、サーバー側のデータの更新作業はユーザーが多い時間にやるべきではありません。

これはアプリの規模感にもよります。もしJSONに不備があっても、すぐに直して挽回可能な規模であれば当てはまりませんが、基本的には深夜層に実施することになるでしょう。深夜まで待機して、ミスったら大クレーム…、そんな作業やりたくない…。

バグのないプログラムがないように、必ず一度はヒューマンエラーが発生します。例えば、iOSAndroidを並行して開発した場合、両者のバージョンは基本的に一致しません。入れ違えただけで大惨事です。

古い端末のユーザーの考慮

AppStore固有の問題として、最新のバージョンとして「iOS7以降でしか動かないアプリ」をデプロイした場合、iOS6未満のユーザーは古いAPKを取得できてしまう というものがあります。

参考: アップル、古い iOSデバイス向けに互換性のある旧アプリを提供 - Engadget Japanese

一度アップロードしたバイナリはAppleによって管理され、開発者は制御できません。闇です。

UPDATE:訂正。アプリケーションのバージョンをiCloudに表示しない(iCloud availability)の設定で、旧バージョンが新規にダウンロードされることは防げる、が正しいです。

個人の感想

  • バージョンチェックは必須、ただし付けるなら認証なり各APIごとにきっちりやるべき
  • 全てのユーザーを強制アップグレードさせて、最新のAPIしか使わせないという選択肢は魅力的だけど、歴史を積み重ねたアプリだと破綻する可能性が高い
  • 「最新=完璧」という前提でいるのは危険
  • 簡単かどうかは実装ではなく運用で決めた方が良い

今更AndroidのToolbarについて理解できたような気がするのでメモ。

気のせいかもしれません。

Toolbar

Toolbar は Action Bar を一般化させたもので、同様の機能を備えつつ、より高い柔軟性を提供します。通常の Action Bar と異なる点は、Toolbar は階層内のビューの 1 つであるということです。そのため、Toolbar のインスタンスは好きなところに配置することができ、他のビューと共存します。さらに、動きを与えたり、スクロール イベントに反応させたりもできます。Activity.setActionBar() をコールすることで、Toolbar を Activity の Action Bar として機能させることもできます。

Android アプリにマテリアル デザインを導入する - Google Developer Japan Blog

これがいまいち意味分からなかったので、原文読んでみました。

Toolbar

The toolbar is a generalization of the action bar pattern, providing similar functionality, but much more flexibility. Unlike the standard action bar, toolbar is a view in your hierarchy just like any other, so you can place instances wherever you like, interleave them with the rest of your views, animate, react to scroll events and so on. You can make the Toolbar act as your Activity’s Action Bar by calling Activity.setActionBar().

Implementing Material Design in Your Android app | Android Developers Blog

generalization of the action bar patternを「Action Bar を一般化」は全然意味違ってないです?「ActionBarパターンを普遍化させた」とかそんな感じのニュアンスに読めます。

toolbar is a view in your hierarchy just like any otherの部分、「他のビューと同じ階層にある」という点についてちょっと曖昧な書き方です。タイトルバー階層と、アプリが管理しているビュー階層が今までは別だったという前提が重要だと思いますので。

interleave them with the rest of your viewsを「他のビューと共存」は意訳なのか自分の訳が悪いのか微妙ですけど、「他のビューの余白に挿入」ってだけに読めます。

ActionBarはビュー階層に解放されました

この記事がとても参考になりました。

~2.XからAndroidにはActivity単位でラベルを表示できるタイトルバーの機能がありました。標準の見た目が残念すぎて、requestWindowFeature()でカスタマイズができるにも関わらず、大抵非表示にされていました。

3.Xでタイトルバーは多機能なActionBarに置き換えられました。しかし「2.Xでタイトルバー非表示にしつつ、3.X~ではActionBarを表示」と分岐を入れるのは好まれず、またActionBarをバックポートできるのはActionBarSherlockという非公式ライブラリしかなかったので、依然非表示にされたまま、ActionBarパターンの認知度はいまいちでした。

その状況が変わったのが2013年7月のAndroid Support Libraryrevision18によるActionBarのバックポートです。時期的には4.3(Jelly Beanの最後のマイナーアップデート)になって、ようやく公式でActionBarがバックポートされ、「iOSとは違うAndroidのパターンを見直そう」という機運が高まります。

そして5.0になるわけですが、ここにきてActionBarの定義が大きく変わったように思います。ロゴ画像ではなくカラーを利用したブランディング、ユーザーの管理するビュー階層への移動、ActionBar組み込みのナビゲーション機能(setNavigationMode())の廃止。

もはやActionBarはユーザービュー階層にあるのですから、その実装はユーザー次第であると考えると、NavigationModeが廃止されたのも理解できます。

しかしタイトルバーを非表示にしてToolbarを使うというのは、直感に反していて非常に微妙…。

2つあるToolbar

Toolbarは2つあります。android.widget.Toolbarandroid.v7.widget.Toolbarです。

Toolbar は AppCompat で完全にサポートされ、フレームワーク ウィジェットと同等の機能と API をもちます。

AppCompat v21 — Lollipop 搭載前のデバイスにマテリアル デザインを! - Google Developer Japan Blog

これ、前提としてandroid.widget.Toolbarがあって、その同等の機能がandroid.v7.widget.Toolbarで提供されている、という意味なのですね…。実際使ってみるまでは、v7ライブラリ専用の機能だとばかり。

両者は実機能としては違いがないのですが、本家がandroid:Theme.Materialテーマを前提としているのに対して、v7版はTheme.AppCompatテーマを前提としており、属性参照している値が異なります。

例によって、android:toolbarStyletoolbarStyleに分裂してるんでしょう。

Toolbarを使うときの注意

setSupportActionbar()を呼んで、ActionBarとして使うときは、以下のようにレイアウト指定します。

<android.support.v7.widget.Toolbar
    android:id="@+id/my_awesome_toolbar"
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:minHeight="?attr/actionBarSize"
    android:background="?attr/colorPrimary" />

そうではなく、普通にViewGroupとして使うときには指定が変わります。

<android.support.v7.widget.Toolbar  
   android:layoutheight="wrapcontent"
   android:layoutwidth="matchparent"
   android:minHeight="?attr/actionBarSize"
   app:theme="@style/ThemeOverlay.AppCompat.ActionBar" /> 

画面に複数Toolbarを表示する場合に、それぞれに異なるスタイルを指定するためなのだと思いますが、トラップ感満載です。

ところで単純なViewGroupとしてみた場合、layout_gravityがレイアウトエディタ上でサジェストされなくて使い勝手が悪いんですけど、バグなんでしょうねー…。

どうでもいいカレンダーの話。

iOSをやってるとあるあるなのが、ユーザーがOSの端末設定を「和暦」に設定してるせいで、取得されるカレンダーが日本のものになってしまい、NSDateFormatterが期待通りに動作しないというもの。

海外のアプリは和暦を考慮してないので上手くいけばクラッシュさせることができます。

西暦

現在普及しているのは西暦です。

個人的に、西暦という呼び方は物凄い雑だと思います。一般にグレゴリオ暦を指しますが、グレゴリオ暦そのものは暦法なのに対して、和暦は紀年法なので、暦法紀年法の区別が付いていないケースが見られます。

1年の長さを定義するのが暦法で、今が何年なのか紀元を定義するのが紀年法です。

単に西暦と呼んだ場合、グレゴリオ暦という暦法と、イエス生誕の翌年を西暦元年とする紀年法両方を指す気がします。

Before Christ(キリスト生誕前)は英語なのに、Anno Domini(主の年)はラテン語という、この良く分からない紀年法は1500年くらい前に考案されるも実際に普及したのは19世紀で、西洋諸国の植民地支配によって世界標準な地位を築きました。

また、実際的にユリウス暦が使われるケースがあることにも注意です。例えば天文学で使われる「1光年」が指すのは、グレゴリオ暦の1年ではなくユリウス暦の1年なのです。

仏暦

仏教徒を中心に、釈迦が入滅した翌年を元年とする仏暦が利用されています。

歴史は浅く、100年くらい前にタイで考案され使われ始めました。

タイは意地でもこの暦を使う気なのか、公文書などにも使いやがります。しかもタイ数字です。読めません。

Wikipediaには太陽暦とのずれがあると書いてあるけどこれは間違ってる気がする?今は普通に543で算出できたような…。

OSの表記などで「タイ仏暦」とあるのは、国によって釈迦入滅の年の解釈、つまり紀元年が違うためです。本当は複数仏暦があるのですがそのうち利用頻度の高い「タイ仏暦」のみ扱われることが多いです。

和暦

日本では1500年ほど元号による紀年法を使い続けています。また、使われていた暦法は以下の通りです。

  • 元嘉暦
  • 儀鳳暦

日本書紀で使われていたとされる暦です。

  • 大衍暦
  • 宣明暦

このころまでは中国で使われていた暦をそのまま日本でも利用していました。日本では暦学や天体観測技術が発達していなかったという事情があります。

  • 貞享暦

ここで初めて国内独自の暦法が採用されました。この辺の話は天地明察が面白いので読むべきです。

あの話だと授時暦の扱いはよくないけど、授時暦の観測精度そのものは、ユリウス暦を超える部分もありました。

  • 宝暦暦

そんな貞享暦は、800年以上続いた宣明暦とは裏腹に、たった70年しか持ちませんでした。

貞享暦による改暦は幕府と朝廷の間の軋轢を生んで、天文方の政治力がなくなったところで、再び土御門家が席捲、この残念な暦を制定してしまったとかどうとか。

天地明察は安井知哲の次男を天文方3代にしたところでハッピーエンドみたいな終わり方してますけど、その後の渋川家の顛末はなんとも切ない。

  • 寛政暦

宝暦暦があまりにも酷すぎたので改定された暦。

わりと現役。今でもカレンダーに書いてある「旧暦」が天保暦のことなのです。

最後の暦ということでかなりの高精度だったながら、2033年に突入するとバグります。

現在使われている暦法。日本で制定されたのは明治6年からなので、明治5年以前を正しく算出するには旧暦への変換が必要で面倒です。

なおグレゴリオ暦が完全な暦法かというとそうではなくて、3000年で1日というレベルながらズレがあり、そもそもグレゴリオ暦の根拠となっている太陽年自体が不変ではないという問題がありますが、生きてるうちは関係なさそうです。

その他

週番号

ヨーロッパのカレンダーで使われます。週に連番振ってるだけなんですけど、月曜始まりなので注意です。

iOS5と6とで、NSDateFormatterYYYYyyyyで取得できる値が変わる現象があって、YYYYの方は週番号ベースだから年が違うみたいなstackoverflow見て信じてたんですけど、あれただのバグだったんですね…(iOS7で直った。でもyyyyを使いましょう)。

iOS8で使えるカレンダー

これらは西暦カレンダーに併記されるという、雑な扱いを受けています。

  • 中国暦

民国紀元のことかと思ったら、時憲暦っぽい。

ヒジュラ暦っぽい。

こちらは普通にユダヤ暦

Androidのカレンダー

Javaは1.4で仏暦を、1.6で和暦をサポートしました。

しかし AndroidJavaじゃない ので、実装を見る限り両方とも使えなさそうです。

今でも和暦を使うところって結構多い(行政とか銀行とか保険屋とか)と思うんですけど、JapaneseImperialCalendarがないAndroidで和暦が使えなくて困った、みたいな話はあんまり聞かないですね。

マテリアルなナビゲーションドロワー。

今のGoogle製のアプリはおおよそこういう見た目になっています。

記事の端末は若干古く、記事のコメントにあるSSのようにステータスバー領域までナビゲーションドロワーが被ってくるようなのがマテリアルなやつらしいです。

で、これどう作るんでしょうね。

NavigationDrawerテンプレート

NavigationDrawerテンプレートでプロジェクトを作ってもこういう動きにはなりません。それどころか、ハンバーガーボタンが動かなくて違和感が酷いです。(自分の環境が最新になってないだけだったらすみません)

これはandroid.support.v4.app.ActionBarDrawerToggleが廃止され、android.support.v7.app.ActionBarDrawerToggleへ移行したのが原因です。

ドキュメントがまだ整備されていなくて、Creating a Navigation Drawer | Android Developersの記述も古いままなんですよね…。

ic_drawer.pngをゴミ箱に投げ捨てて、インポートするActionBarDrawerTogglev4からv7に変えましょう。

//android.support.v7.ActionBarDrawerToggle
mDrawerToggle = new ActionBarDrawerToggle(getActivity(), 
    mDrawerLayout, 
    R.string.navigation_drawer_open, 
    R.string.navigation_drawer_close)

ただこれも過渡期の、ハンバーガーボタンが矢印にアニメーションするやつで、今風ではないのです。

ActionBarの上にドロワーを載せるには?

どう頑張っても無理だと思うんです。ビュー階層がそもそも違うので。

アプリケーションの最上層には、Window#getDecorView()で取得できる、android:id/dector_content_parentがあって、android:id/action_bar_containerandroid:id/contentxmlで指定したレイアウト)はその子要素となっているはずなのです。

というわけで、適当にGmailアプリのビュー階層をダンプしてみました。

f:id:quesera2:20150110133817p:plain

com.google.android.gm:id/action_bar_rootの下にandroid:id/contentがあります。ドロワーはその子要素となっています。

ActionBarっぽく見えてるのはさらにその下にあるcom.google.android.gm:id/mail_toolbarというただのViewです。

これはサポートパッケージのActionBarActivityを使った上で、

<item name="windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>

ActionBarを消し去った上で、さらに代替としてToolbarを使っているっ挙動っぽい。

ioschedの実装を読もう

マテリアルデザインのお手本とされているioschedを読んでみます。

google/iosched · GitHub

前読んだときは、UI部分はスルーしてました。

src/main/res/values/styles.xmlより、

<style name="Theme.IOSched.Base" parent="Theme">
  ...(省略)
  <item name="windowActionBar">false</item>
  <item name="android:windowNoTitle">true</item>
  ...(省略)
</style>

<style name="Theme.IOSched.WithNavDrawer" parent="Theme.IOSched" />

src/main/res/values-v21/styles.xmlより、

<style name="Theme.IOSched.WithNavDrawer" parent="Theme.IOSched">
  <item name="android:statusBarColor">@android:color/transparent</item>
</style>

アクションバー消してるのは予想通り。stylesで空のテーマを作っておいて、v21だけステータスバーを透明にしてます。v21なんですね。4.4のimmersive mode(あまり知らない)だと思ってたので意外。

src/main/com/google.samples/apps/iosched/ui/BaseActivity.javaより、

// Primary toolbar and drawer toggle
private Toolbar mActionBarToolbar;

protected Toolbar getActionBarToolbar() {
  if (mActionBarToolbar == null) {
    mActionBarToolbar = (Toolbar) findViewById(R.id.toolbar_actionbar);
      if (mActionBarToolbar != null) {
        setSupportActionBar(mActionBarToolbar);
      }
    }
  return mActionBarToolbar;
}

ですよねー。

setSupportActionBar()ってもうこのために存在するメソッドとしか思えませんでしたし…。

setSupportActionBar()というのは、引数に渡したandroid.support.v7.widget.ToolbarをActionBarとして利用するメソッドです。

本物のActionBarをThemeで非表示にした上で、レイアウト上にあるToolbarをActionBarとして利用することによって、画面全体にナビゲーションドロワーが表示されるようにしているのです。

private void goToNavDrawerItem(int item) {
  Intent intent;
  switch (item) {
    case NAVDRAWER_ITEM_MY_SCHEDULE:
      intent = new Intent(this, MyScheduleActivity.class);
      startActivity(intent);
      finish();
      break;
...(以下略)

ドロワーからアイテム選択されたらstartActivity()した後、自身をfinish()してます。

つまり、ドロワーのルートになる全てのレイアウトがToolbarNavigationDrawerのリスト部分をincludeしてるんですね。ドロワー内のリストの選択状態は各Activityで管理なんでしょうか。

ドロワーが閉じてる最中にstartActivity()したら見た目の整合性取れないよね?と思ったら、postDelayed()startActivity()にディレイを掛けて、ドロワーが閉じた後に移動するよう見せかけてます。

これ微妙すぎるのでは…。

ActionBarActivityを使わない場合

Activity | Android Developers

API Lv21以降はsetActionBar()setSupportActionBar()と同じことができます。

ただし、この引数のToolbarandroid.support.v7.widget.Toolbarではなく、 android.widget.Toolbarです。両者は全く別物です…。

Androidのサポートパッケージについて

v17 Leanback Libraryの存在はとりあえず無視しておくとして、Androidのサポートパッケージは何種類かあります。

たぶんv13パッケージはなぜ存在するのか知らない人が多いと思いますので備忘録も兼ねて。

v4 Support Library

まず、サポートパッケージのv4とは「サポートパッケージのversion4」ではなく、「AndroidAPI Lv4以上で利用できるサポートパッケージ」を意味しています。

v4はAndroid 1.6 Donut以上で使えるライブラリで以下の機能を持ちます。

互換性のための機能

  • 3.0で追加されたFragmentのサポート
  • 3.0で追加されたLoaderのサポート
  • Notification系のメソッド@Deprecatedが多く、通知できるスタイルも4.1で大幅に増えたのですが、NotificationCompatを使うことでその辺をそれほど意識しなくて済む…かも?

新機能

  • LocalBroadcastManager。ブロードキャストレシーバーは端末全体に通知するけど、「ローカル」な「ブロードキャストレシーバー」はアプリ内部にのみ通知するためセキュア。実装がすごい短くて面白い。アプリ内部で完結する通知を実装したいときにどうぞ。
  • ViewPager。スワイプでページを切り替えるインターフェース。
  • SlidingPaneLayout。マルチペインレイアウトを実現するレイアウト。
  • DrawerLayout。ナビゲーションドロワーの、ドロワーの部分を実現しているレイアウト。「ナビゲーションドロワーにはActionBarが必要」みたいな固定概念がありますが、実はこれ単品でも使えます。

興味がないのであまり知らない

  • アクセシビリティ系の互換ヘルパ
  • FileProvider複数アプリ間でファイルを共有する機能を提供する。標準の連絡帳やギャラリーでは、パーミッションがなくてもIntentで呼び出されたときのみ、ユーザーの選択したアイテムだけ、呼び出し元アプリに一時的にアクセス権限を与える機能があるけれど、それのファイルバージョンみたいなものとふわふわ理解してる。

v7 Support Library

v7はAndroid 2.1 Eclair 以上で使えるライブラリで以下の機能を持ちます。

互換性のための機能

  • 3.0で追加されたActionBarのサポート
  • ActionBarActivity
  • ShareActionProviderSNS連携を実装するときに便利っぽいのだけれど…。

現在は生のActivityを使わずに、ActionBarActivityを継承するスタイルを推奨しています。

この場合アプリテーマはAppCompatを継承する必要があって、これのせいでリソースファイルの見通しが悪くなるのが辛いところ(リソースに名前空間がないから、重複回避にabc__を使ってるせいで候補として真っ先に上がってくるのが辛い)。

AppCompatでいくつかのコンポーネントを作ると、マテリアルな感じにtintカラーを付与してくれます。

  • 3.0で追加されたGridLayoutのサポート
  • ついでにSpaceもバックポート。(GridLayoutのために存在するのだけど、それ以外で使っても割と便利)
  • Switchがようやくバックポート…。

新機能

  • Cardview。カードっぽく見せることができるリストビューのアッパーバージョン。これ必要あります?
  • RecyclerView。削除・追加にアニメーションを付けられるリストビューのアッパーバージョン。5.0以降で使う場合、LayoutManagerを設定しないとクラッシュすることに注意。ただ、LayoutManagerを設定することでグリッド、横方向のリストも作れます。

ListViewに変わるコンポーネントとしていくつか提案されてますが、歴史あるListViewと比べるとノウハウが蓄積されていないので、変なところでハマって無駄な時間を食ったりします。

興味がないので知らない

  • v7 mediarouter library。Choromecastとかその辺?

v8 Support Library

API Lv13から提供された、RenderScriptをv8以降で使えるようにするというものです。

RenderScriptについては…迷走してる感があってもにょい。

この辺、自分の理解度が高いと言えない領域なのでなんとも言えないのですが、当初はOpenGLを置き換えるようなアピールがされてたんですけど、JellyBeanからは描画関連の処理がバッサリカットされて、GPGPUによる高速計算を行うクラスになったっぽい??

あとGPCPUを使えない端末にまでバックポートできてしまうのだけど、そのときは普通にCPU使うらしいですね。

C99頑張って書く労力に見合ってないと思うんですよ…。

v13 Support Library

ついに本題。

v13 Support Libraryって何のためにあるのか知らない人多いと思うんですよ。

これは「v4でバックポートされたFragmentを使わない」ためにあります。

例えば、ViewPagerFragmentPagerAdapterで使う場合を考えると、こいつのコンストラクタandroid.support.v4.app.FragmentManagerを要求するんです。

// OK
mAdapter = new FragmentPageAdapter(getSupportFragmentManager()){
    ...(省略)
});

API Lv13以降の普通のActivitygetFragmentManager()で取得されるFragmentManagerandroid.app.FragmentManagerなので、型の不一致でビルドが通らないわけです。

// NG
mAdapter = new FragmentPageAdapter(getFragmentManager()){
    ...(省略)
});

ではViewPagerを使うときには、必ずFragmentActivityActionbarActivityを使わなければならないのでしょうか?

いいえ、そこでv13サポートライブラリが使えるのです。

//OK
mAdapter = new android.support.v13.app.FragmentPagerAdapter(getFragmentManager()){
    ...(省略)
});