tanamonの稀に良く書く日記

KEEP CALM AND DRINK BEER

[memo]UDID/UUID/UIIDなどとiOS6の新IDの違い

UなんとかIDみたいなのがいっぱいあって区別がつかないので少し整理してみた。


なんとかIDの種類。

UDID(Unique Device IDentifier)

(たぶん)Apple用語。
iOS端末の製造時に割り当てられる固有の識別コードで、値の変更はできない。
端末IDや端末固定IDと呼ばれるものと同じ。
iOS5からアプリからの取得が非推奨になった。

UUID(Universally Unique IDentifier)

RFC 4122で定義されている。
生成の度に値が変わり、理論上重複することがない。
実装的にはGUID(Globally Unique IDentifier)が有名。
iOS6からNSUUIDクラスを使って簡単に生成できるようになった。

UIID(Unique Installation IDentifier)

インストールごとに変わるという性質を持ったUUID。
そのため、アプリを複数回インストールするとその都度別の値になる。
アプリの初回起動時にUUIDを生成してストレージに保存しておくという実装が一般的かと思われる。

OpenUDID

GitHub - ylechelle/OpenUDID: [OpenUDID IS NOW DEPRECATED] Open source initiative for a universal and persistent UDID solution for iOS
iOS端末のUDIDへのアクセスが禁止されたことによる代替案らしい。
性質はUDIDとほぼ同じで、オプトアウトできる(= 拒否権を行使できる、要は利用者都合で値を再生成できる)。
実装はiOS/Android/Windows Phoneがあるが、オプトアウトはiOS版のみ可能。

SecureUDID

GitHub - crashlytics/secureudid: DEPRECATED - SecureUDID is an open-source sandboxed UDID solution aimed at solving the main privacy issues that caused Apple to deprecate UDIDs.
OpenUDIDがセキュアじゃない(特に複数ベンダー間で同一値を用いるところ)ため、代替案として作られたもの。
OpenUDIDと比べると、ベンダーごとに違う値が生成されるという点が異なる。
実装は今のところiOSのみ。

UIDevice.identifierForVendor

UDIDの代替としてiOS6から使える公式実装。
端末固定でベンダーごとに値が変わるので、性質的にはSecureUDIDに近い。
ターゲットをiOS6以降にできるなら、SecureUDIDの代わりにこちらを使った方がいい。

ASIdentifierManager.advertisingIdentifier

UDIDの代替としてiOS6から使える公式実装(その2)。
UIDevice.identifierForVendorとは違い、全ベンダー共通のためUDIDに近い。
ただし、UDIDと違い、オプトアウトできる。
(オプトアウトは設定アプリの情報>アドバタイズにある「Ad Trackingを制限」で設定)

特徴

で、それぞれ、どの程度一意性があるかをまとめてみるとこんな感じになった。

一意性の範囲 UDID UUID UIID OpenUDID SecureUDID IDFV ASID 電話番号 MACアドレス
永久一意性*1 ×*2
IDを利用する度 ×
再インストール × ×
同V複数アプリ間 × ×
複数ベンダー間 × × × ×
機種変更 × × × × × × × ×
複数機種利用 × × × × × × × × ×
利用者の変更*3 × × × × × × ×

(比較のために他の一意情報である電話番号とMACアドレスを入れてみました)
○ = 値が変わらない、× = 値が変わる


こうして一覧にすると、

  • UDIDとMACアドレスは、他人の手に渡った後も同一IDとなってしまう(かなりキケン)
  • 電話番号は、将来的に他人と紐付けてしまう可能性があるため、そもそも一意かという点で微妙(キケン)
  • OpenUDIDは、IDが漏洩すると利用者の意図しない範囲までの情報が紐づけ可能となる(キケン)

ということがわかる。これらは一意性を保つための情報としては不適切じゃないかと思う。

ここらへんの危険物を避けた上で、残りものを用途別に見ていくと、

UUID

端末内の一意な名称(テンポラリなファイル名など)を区別するために使う。
ただしサーバが介在する場合は、サーバ側でUUID相当のものを発行した方がいいと思う。
(ちなみに、ありがちな{年月日時分秒}.pngみたいなのは、端末時刻をユーザが変更できる環境では一意になるとはいえないため、UUIDを用いること)

UIID

ユーザ認証を持たずにユーザを特定して、サーバとの通信を行うような場合に使う。
アプリ間で共通のIDを持つ必要性がない場合はこれを使うのがよい。
(基本的に意図せぬ範囲にIDが公開されないように、共通性は抑えておいたほうがよいため)

SecureUDID

複数のアプリを提供しているベンダーが、ユーザを特定するためにUDIDの代わりとして使う。
iOS5以前の環境でも利用したい場合のみ、iOS6以降だけならUIDevice.identifierForVendorを使う。

UIDevice.identifierForVendor

複数のアプリを提供しているベンダーが、ユーザを特定するためにUDIDの代わりとして使う。
(使い勝手がいいということで)今後はこれが主流になるかと*4

ASIdentifierManager.advertisingIdentifier

iAdのような広告提供用ライブラリ内で使うなど、かなり特殊用途だと思う。
オプトアウトできるとはいえ、普通の開発者は手を出さないほうがいいかと。


なお、これらのIDでカバーされていない領域の機種変更・複数機種利用は、ここら辺はOAuthなどのアクセストークンと組み合わせて繋げておくべきところだと思う。

*1:同じIDが今後も含め二度と振られないという(理論上ほぼ完全な)一意性を持つかどうか

*2:たしか携帯電話番号は解約してしばらく経つと同じ番号が振られたはず

*3:中古屋さんに売ったり、友人に譲渡したりというような想定

*4:個人的にはこれ単体で一意とするのではなくUIIDと併用するようにして、必要最低限のものだけ持つように実装してほしい

[memo]Xcodeエラー切り分け

よく出る、

clang failed with exit code 255
A signed resource has been added, modified, or deleted.
コード上絶対に間違っていない箇所なのにビルドエラーになっている
Step実行時にソース行と一致しなかったり、Breakpointが変なところで効いたりする

あたりの現象の話。


これに限らずXcodeを使っていてさっきまで動いていたのに急に摩訶不思議な動きをした場合は、以下のことをやる。

1.もう一度Buildする

exit code 255とかはこれでうまくいくことが多い(なんで?)

2.CleanしてからBuildする

これで直るとうれしい。

3. 一度プロジェクトを閉じた上で、Window > Organizerから該当プロジェクトのDervied Dataを削除する

これで直ることが多いので、最近は2.を飛ばしてる。

4. OSを再起動する

たまにこれで直ることがある。


ここまでやって直らない場合は、Xcodeの問題というより自分でいじった部分の問題っぽいので、あれこれ切り分ける。
たとえば、人からもらったプロジェクトの場合は、相手のXcodeのバージョンを聞いて自分の方が古かったらアップデートすると動いたりとかする。


なんにせよ、もうちょっと安定して動いてくれないですかねー。

iOS6で利用できる機能

iOS - 利用できる機能 - Apple(日本)
ここの一覧が見づらいので日本で使えるかどうかを抜き出してみた。

マップ 標準
マップ 航空写真
マップ 道順
マップ ルート案内機能
マップ 建物の3D表示 ×
マップ 渋滞状況 ×
マップ ローカル検索
マップ ビジネスレビュー&写真 ×
Siri スポーツ
Siri Twitterの統合
Siri Facebookの統合
Siri ローカル検索 ×
Siri レストラン情報 ×
Siri レストランのレビュー ×
Siri レストランの予約 ×
Siri 映画情報
Siri 映画のレビュー ×
Siri 上映時間 ×
iTunes Store ミュージック
iTunes Store 映画
iTunes Store テレビ番組 ×
音声入力 音声入力
App Store アプリケーション
App Store ゲーム

iMacが再起動を繰り返す病にかかったようです

iMac 24inch mid 2007での話。

SMCをリセットする

まずは、SMCのリセットを試す。
Mac の SMC (システム管理コントローラ) をリセットする方法 - Apple サポート

直らなかった。

AHT(Apple Hardware Test)を実行する

Mac で Apple Hardware Test を使う方法 - Apple サポート
Dキーを押しながら電源ONで起動させても、OSが通常起動してしまう。
なんで?


Mac で Apple Hardware Test を使う方法 - Apple サポート

Apple Hardware Test を実行するには「Install DVD」から起動する

コンピュータの光学式ディスクドライブに「iMac OS X インストールディスク 1」インストール DVD を挿入します。
キーボードの「D」キーを押したまま、コンピュータを再起動します。

Install DVDを引っ張り出してきて試してもやっぱり起動しない。


http://support.apple.com/kb/PH11342?viewlocale=ja_JP

コンピュータにシステム・ソフトウェア・ディスクまたは USB フラッシュドライブが付属している場合は、これらを使用して「Apple Hardware Test」を起動できる場合があります

なんか説明に含みがあるし。
しかも「できる場合がある」って、できないケースのほうが多いってことじゃないか?

AHTをインストールする

なんで起動しないのかをよく考えてみたら、一つ心当たりがあった。
Snow LeopardからLionへのアップデート時にHDDを交換していて、移行アシスタント経由でアップデートを行っていたんだった。
おそらくAHTのプログラム自体は入っているけど、BIOSから起動できる状態にはなってないんだろう。

となると、何とかしてAHTをインストールしないといけないんだけど、単体で入れられるものなのだろうか?


Apple Hardware Testの起動方法: Apple サポートコミュニティ

Snow Leopard Install DVDにはApple Hardware Testは入っていません。Mac付属のInstall DVDでInstallして下さい。
# CPU Help FilesがAHTそのものです。

/System/Installation/Packages/CPU_AHT.pkg
取り出しておくと便利かも。

やっぱりOSのアップデートディスクにはAHTは入ってないらしい。
ただし、Install DVDから入れ直しができるっぽい。


というわけで、途中で再起動されながらもOSを通常起動させてインストールしてみた。
Install Bundled Software Onlyのインストーラを起動させて、インストールの種類のカスタマイズから「CPU Help Files」だけをチェックしてインストールすればOKです。

AHTを実行する

今度はD押しながら電源ONで起動できた。

しかし、マウスカーソルが出ているがトラックパッドが認識しない。
BluetoothじゃなくてUSBもののデバイスじゃないと認識されないのかもしれない。
仕方なくキーボードで言語を選択する。


システム構成がスキャンされた後、キーボードのTキーでテスト実行できるので、早速実行する。
が、テストしてもエラーはでなかった。
「全テストを実行します」というとてもチェックしたい項目があるのだけど、キーボードでチェックさせる方法がわからない。
とりあえず、再度テスト。

警告:Apple Hardware Testがエラーを検出しました。

4MEM/4/40000000: 4a2801f8

今度はエラーがでた。

何回か実行させた結果

1回目: 問題は発見されませんでした
2回目: 4MEM/4/40000000: 4a2801f8
3回目: 4MEM/4/40000000: da1a44c
4回目: 問題は発見されませんでした
5回目: (テスト中に再起動)
6回目: 問題は発見されませんでした
7回目: (放置していたら再起動)

うーん、4MEMはメインメモリのエラーなように見えるけど、テスト中の再起動はロジックボードの問題かもなぁ。
寿命なのかもしれない。


結局、2GBのメモリが2500円くらいで売ってたのでダメモトでぽちって交換待ちということにしました。
直らなかったら9/12にされるであろう新型発表後に新しいiMacを買う(かも)。

SQLiteでOracleのTRUNC関数のようなことをする

日付だけならできる。

sqlite> select datetime('now', 'start of day');
2012-08-28 00:00:00

sqlite> select datetime('now', 'start of month');
2012-08-01 00:00:00

sqlite> select datetime('now', 'start of year');
2012-01-01 00:00:00