NSUserDefaults - アプリケーション出荷時設定

2010年9月7日火曜日 | Published in | 0 コメント

このエントリーをはてなブックマークに追加

NSUserDefaultsにはアプリケーション出荷時設定を登録することができる。

-アプリケーション出荷時設定


-[NSUserDefaults registerDefaults:] を使う。

User Defaults Programming Topics: Using NSUserDefaults より引用

+ (void)initialize{
 
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSDictionary *appDefaults = [NSDictionary
        dictionaryWithObject:@"YES" forKey:@"DeleteBackup"];
 
    [defaults registerDefaults:appDefaults];
}

アプリケーションで NSUserDefaults へ値を保存した場合、上記値は上書きされる(ユーザの設定が優先される)。


ドメイン


NSUserDefaults には5つのドメインが存在する。
User Defaults Programming Topics: Defaults Domains より引用


表の順番が優先順位となっている。先程の -[NSUserDefaults registerDefaults:] で登録される値は NSRegistrationDomain に所属する。

アプリケーション実行中に -[NSUserDefaults setObject:forKey:] で登録される値は Application (Domain)に所属する。この設定は下記のファイルに保存される。
$HOME/Library/Preferences/<ApplicationIdentifier>.plist;

参考情報


NSUserDefaults Class Reference

iOS デバイスでの番号・番号・番号( UDID、ICCID、IMEI、... )

2010年9月6日月曜日 | Published in | 0 コメント

このエントリーをはてなブックマークに追加

ケータイでいう端末識別番号に近いものが iPhone にないか調べてみた。その簡単なまとめ。

[2010-09-17追記]
・ECID
・参照情報



[2011-11-11追記]
・IMEIの取得方法


番号一覧


名称 説明 格納先
UDID デバイス識別子
(Unique Device IDentifier)
デバイス ffc1ded6f4570d557ad65f986684fc10c7f8d51f
シリアル番号シリアル番号 デバイス 12345ABCDEF
Wi-Fiアドレス無線LANデバイスのMACアドレス デバイス 00:12:08:23:7D:A2
ICCID 携帯電話に付与される番号 SIMカード 1234 5678 1234 5678 123
IMEI 携帯電話に付与される番号 デバイス 12 123456 123456 0
IMSI 携帯電話ユーザーに付与される番号 SIMカード 12 123456 123456 0
ECID デバイス識別に使われる16桁数値(16進)
Exclusive Chip Identification
デバイス 9999902578999
3G 接続できない iPod/IPad Wifi には当然ながら ICCID, IMEI, IMSI は存在しない。

ICCID

Subscriber Identity Module - Wikipedia, the free encyclopedia より引用
Each SIM is internationally identified by its ICC-ID. ICC-IDs are stored in the SIM cards and are also engraved or printed on the SIM card body during a process called personalization. The ICC-ID is defined by the ITU-T recommendation E.118.[9] According to E.118 the number is up to 19 digits long including a single check digit calculated using the Luhn algorithm. However, the GSM Phase 1[10] defined the ICC-ID length as 10 octets with operator-specific structure.

IMEI

International Mobile Equipment Identity - Wikipedia より引用
International Mobile Equipment Identity (IMEI) は、GSM/W-CDMA/iDENの全ての携帯電話や一部の衛星電話に付与される識別番号。携帯電話のバッテリを外すと、そこに書いてあることが多い。また、*#06# と入力すれば携帯電話の画面にも表示できる。
GSMのネットワークでは、正当なデバイスかどうかを識別するのに使われており、盗まれた携帯電話を使えないようにすることもできる。例えば携帯電話を盗まれた場合、携帯電話会社に電話してそのIMEIの電話でネットワークにアクセスできないようにしてもらうことができる。そうするとその電話はSIMカードを入れ替えても使えなくなる。

IMSI

International Mobile Subscriber Identity - Wikipedia より引用
International Mobile Subscriber Identity(IMSI、「イムズィ」と発音)は、GSMおよびW-CDMAの全ての携帯電話ユーザーに割り当てられている一意な識別番号。携帯電話内のSIMカードに格納されており、その電話からネットワークに送信される。Home Location Register (HLR) やそのローカルなコピーである Visitor Location Register (VLR) から、その携帯電話に関する詳細を引き出すのにも使われる。
SIMカード - Wikipediaより引用
SIMカードには、IMSI(International Mobile Subscriber Identity)と呼ばれる固有の番号が付与されており、これと電話番号を結びつけることにより通信を可能とする。SIMカードを抜き差しすることで、電話番号を他の携帯電話機に移したり、ひとつの携帯電話端末で複数の電話番号を切替えて使用したりすることができる。

ECID

Exclusive Chip ID - Wikipedia, the free encyclopedia より抜粋
An Exclusive Chip ID, or ECID is a 16-digit Hexadecimal number used to uniquely identify Apple iOS devices[1].
The ECID of a device is used by Apple, in combination with a hashcode of the firmware as a challenge key in a challenge-response authentication protocol.

ECID - The iPhone Wiki より抜粋
With the iPhone 3GS onward, the ECID tag with your ECID is put in the signature checked section of every firmware file, and sent to Apple's servers for re-signing to get a valid SHSH.

「Jailbreakは合法」の決定、Appleは対抗するのか - ITmedia News
上記ソースによれば「基地局が端末を識別するのに使う番号」とのこと。

[関連]SIMカード

SIMカード - Wikipediaより引用
SIMカード(シムカード、Subscriber Identity Module Card)とは、GSMやW-CDMAなどの方式の携帯電話で使われている電話番号を特定するための固有のID番号が記録されたICカード。

関係など

ICCIDの取得方法について - 日本Androidの会 | Google グループ より引用
ICCIDやIMSIではSIMの識別ができ,IMEIを使用すると端末の識別ができます。
CCIDはICに紐づく番号ですので、SIMの紛失・破損等があった場合はICCIDは
変わってしまいます。
IMSIに関しましては契約者に紐づくため、電話番号とユニークになります。
しかし問題が一点あり、IMSIは再利用される可能性を含みます。
ICCIDは,皆様ご指摘のとおり,SIM固有の番号です。
IMSはI (International Mobile Subscriber
Identity)であり,ドコモなどの携帯事業者がSIMに割り当てた識別コードです。
したがってICCIDがIMSIを特定できれば,SIMを特定できます。
携帯電話の通信では,IMSIが電話番号の代わりをします。
SIMがないと,電話番号がなくなることになるため,通信できなくなります。

確認方法など

iPhoneの場合、設定 > 一般 > 情報で シリアル番号、IMEI、ICCID が確認できる。

同様に iTunesでもシリアル番号、IMEI、ICCIDが確認できる。シリアル番号をクリックすると UDID(識別子)も確認できる。

ECID は Xcodeのオーガナイザで見ることができる。

参考

iPhone:シリアル番号、IMEI、ICCID 番号を確認する方法
iPad:シリアル番号、UDID、IMEI、ICCID、およびセルラーデータ番号を確認する


プログラムでの取得方法


UDID

UIDevice 経由で取得できる。
[UIDevice currentDevice]. uniqueIdentifier 
[考察] UUIDを認証に使った場合、他者に漏れると簡単になりすましができてしまう。この為、認証に使ってはいけない。また生のまま暗号化されていないネットワークに流すことや、サーバ側で管理することも推奨されない(UUIDを元に個人が特定できる可能性が出てくるため、漏洩した場合まずいことになる)。ログを取る目的などで単にユーザを分別するのに利用したい場合は、適当な文字列(SALT)を加えてから MD5や SHAなどのハッシュ関数を通した値を使うと良い。SALTが漏れると意味が無いのでこれは秘密にしておく。なおSALTを単純にソースに埋め込んだ場合、実行バイナリを解析されるとすぐにバレてしまう可能性がある。簡易な方法としては、適当な文字列に加え、他の複数のデバイス固有情報(の一部)を SALTに加えると良いと思われる(シリアル番号やWiFiアドレス他)。(2010-09-17 追記)参考情報記載の Togetter の高木さんの発言によればユーザ識別用途なら乱数の使用が望ましいとのこと。端末固有の情報をいくら組み合わせても端末特定は可能なため。

シリアル番号

取得方法不明 ※情報求む

Wi-Fiアドレス

以下を参照 ※未確認
How can I programmatically get the MAC address of an iphone - Stack Overflow

ICCID

取得方法不明 ※情報求む

IMEI


2011-11-11 追記
エリカ女史が IMEIを取得するコードを公開していた。IOKit 利用。
UIDevice-IOKitExtensions.m at master from erica/uidevice-extension - GitHub

試したところ iPhone 4S (iOS 5.0.1)では取得できなかった。ネット上では iPhone OS 3.2.2 の時は取得成功、iOS 4.3から取得できなくなったとの情報あり。
iphone - Device IMEI using uidevice-extension - Stack Overflow
Device currentDevice] imei]

また IOKit 自体を iOS においては非パブリックとみなす人が多く、App Store審査で却下されるとの意見も多い。
iphone - Will use of IOKit in my iOS app get my app rejected? - Stack Overflow

エリカ女史自身もなんとなく歯切れの悪い説明。
iPhone Dev: IOKit - The Missing Public Framework - O'Reilly Broadcast

非パブリックの原因として上げられている理由:ドキュメントが無い、ヘッダファイルが無い
一方で PrivateFrameworks ディレクトリに含まれていないのでパブリックだという意見もある。

どちらにせよ iOS 4.3以降で IOKit 経由でIMEIを取得する方法は現在のところ不明。


IMSI

取得方法不明 ※情報求む

ECID

取得方法不明 ※情報求む


参考情報

Togetter - 「iPhoneアプリ「電波チェッカー」がUDID偽装可能だったことが発覚してからのまとめ」
アップル、iPhoneに対するジェイルブレイキングの弊害を強調 : [特集]iPhone/iPad - Computerworld.jp
「ECIDの変更が可能になれば、利用者の身元を特定できなくしたり(麻薬取引を行っている人物などには好都合)、通話料の請求を免れたりすることも可能になる」(Appleの提出文書より)
- - - - 間違いや補足、情報などあれば是非教えて下さい。追記・訂正します。

NSBlockOperation を使って並行処理

2010年9月5日日曜日 | Published in | 0 コメント

このエントリーをはてなブックマークに追加

iOS 4 から追加された NSBlockOperation を使うと簡単に並行処理が書ける。

NSBlockOperation


NSBlockOperation Class Reference

NSBlockOperation は従来 -[NSOperation main] に実装していた処理を Blocksで書くことができる。こんな感じ。
NSBlockOperation* operation = [NSBlockOperation blockOperationWithBlock: ^{
    // 処理1
}];

NSOperation のサブクラスなので実行開始は start を投げてやればよい。
[operation start];
複数の処理を走らせたい時は addExecutionBlock: で処理 Blocksを追加していく。
[operation addExecutionBlock:^{
     // 処理2
}];
終了時に処理を実行したい場合は iOS4 から NSOperation に追加された setCompletionBlock: で処理を指定しておくことができる。
NSOperation Class Reference - setCompletionBlock:

[operation setCompletionBlock:^{
    // 終了時処理
}];
なお start で実行した後は、すべての処理が完了するまでその場でブロックされる。


サンプル


NSBlockOperation を使ったサンプルプログラムを作って動きを確かめてみた。

実行すると2つの処理が同時に走る。thread1は1秒間隔でラベルを更新していく。thread2の方は2秒間隔で更新する。

ソースコードはこんな感じ。
- (IBAction)start:(id)sender
{
 NSLog(@"setup");

 NSLog(@"1: %@", [NSThread currentThread]);
 NSBlockOperation* operation = [NSBlockOperation blockOperationWithBlock: ^{
  NSLog(@"2: %@", [NSThread currentThread]);
  for (int i=0; i < 10; i++) {
   [label performSelectorInBackground:@selector(setText:)
         withObject:[NSString stringWithFormat:@"running: %d", i+1]];
   [NSThread sleepForTimeInterval:1.0];
  }
 }];

 [operation addExecutionBlock:^{
  NSLog(@"3: %@", [NSThread currentThread]);
  for (int i=0; i < 5; i++) {
   [label2 performSelectorInBackground:@selector(setText:)
         withObject:[NSString stringWithFormat:@"running: %d", i+1]];
   [NSThread sleepForTimeInterval:2.0];
  }
 }];

 [operation setCompletionBlock:^{
  NSLog(@"completion");
  label.text = @"completion";
  label2.text = @"completion";
 }];

 NSLog(@"start");
 [operation start];
 
 NSLog(@"end");
}
UILabelの更新はメインスレッドで行う必要があるため -[NSObject performSelectorInBackground:withObject:] を使っている。

動作中のコンソール:
setup
1: <NSThread: 0x590db20>{name = (null), num = 1}
start
2: <NSThread: 0x590db20>{name = (null), num = 1}
 3: <NSThread: 0x5d36840>{name = (null), num = 3}
end
 4: <NSThread: 0x5d36840>{name = (null), num = 3}

これを見ると次のことがわかる。
  1. 1番目の処理はメインスレッドで走っている(NSThreadが同じ)
  2. すべての処理が完了するまでブロックされる
  3. completion処理はブロック解除後に非メインスレッドで実行される

最後の動作が腑に落ちない感じもするがそういうものなのだろう。

ソースは GitHub からどうぞ。
WaitScreenSample at 2010-09-05 from xcatsan's iOS-Sample-Code - GitHub


実機での動作


ここまでは iPhone シミュレータでの話。
実機で走らせるとまた違った動作になった。
setup
1: <NSThread: 0x105210>{name = (null), num = 1}
start
2: <NSThread: 0x105210>{name = (null), num = 1}
3: <NSThread: 0x105210>{name = (null), num = 1}
end
 4: <NSThread: 0x151820>{name = (null), num = 18}

メインスレッドだけで処理が走っている?実際画面上の動作を見ても thread1 のカウントアップが終了した後、thread2のカウントアップが走る。同時には動作しない。

うーむなぜだろう。書き方が悪いのか?
...今日は時間切れ。



参考情報

Concurrency Programming Guide: Operation Queues (日本語訳) - steelwheelsの日記
Concurrency Programming Guide: Introduction
Using Concurrency To Improve Responsiveness
Togetter - 「【技術情報】iOS 4のNSOperationはGCD使用か否かの俺様用まとめ」

アプリのバージョン番号を取得する(メモ)

2010年9月4日土曜日 | Published in | 0 コメント

このエントリーをはてなブックマークに追加

アプリのバージョン番号を取得するメモ。

バンドル内に配置される *.plist から取得すればいい。

こんな感じ。

[[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString*)kCFBundleVersionKey];

代表的なキーは CFBundle.h で定義されている。以下、引用:
/* ===================== Standard Info.plist keys ===================== */
CF_EXPORT
const CFStringRef kCFBundleInfoDictionaryVersionKey;
    /* The version of the Info.plist format */
CF_EXPORT
const CFStringRef kCFBundleExecutableKey;
    /* The name of the executable in this bundle, if any */
CF_EXPORT
const CFStringRef kCFBundleIdentifierKey;
    /* The bundle identifier (for CFBundleGetBundleWithIdentifier()) */
CF_EXPORT
const CFStringRef kCFBundleVersionKey;
    /* The version number of the bundle.  For Mac OS 9 style version numbers (for example "2.5.3d5"), */
    /* clients can use CFBundleGetVersionNumber() instead of accessing this key directly since that */
    /* function will properly convert the version string into its compact integer representation. */
CF_EXPORT
const CFStringRef kCFBundleDevelopmentRegionKey;
    /* The name of the development language of the bundle. */
CF_EXPORT
const CFStringRef kCFBundleNameKey;
    /* The human-readable name of the bundle.  This key is often found in the InfoPlist.strings since it is usually localized. */
CF_EXPORT
const CFStringRef kCFBundleLocalizationsKey CF_AVAILABLE(10_2, 2_0);
    /* Allows an unbundled application that handles localization itself to specify which localizations it has available. */

+[NSThread callStackSymbols]でコールスタックのダンプ

2010年9月3日金曜日 | Published in | 0 コメント

このエントリーをはてなブックマークに追加

iOS 4 から NSThread にクラスメソッド +callStackSymboles が追加された。これはその時点でのコールスタックの内容を配列で返してくれるというもの。
NSThread Class Reference - callStackSymboles

例えば適当なメソッドでコンソールへ出力すると:
- (void)changeStateOfSwitch:(id)sender
{
 NSLog(@"%@", [NSThread callStackSymbols]);
}

こうなる。
0   SampleApp     0x00037936 -[PreferenceViewController changeStateOfSwitch:] + 44
 1   UIKit             0x000d2e14 -[UIApplication sendAction:to:from:forEvent:] + 119
 2   UIKit             0x002a1c41 -[_UISwitchSlider sendAction:to:forEvent:] + 104
 3   UIKit             0x0015e71b -[UIControl(Static) _sendDelayedActions:] + 477
 4   UIKit             0x0015c5cf -[UIControl(Internal) _sendDelayedActions] + 42
 5   UIKit             0x001d8e47 -[UISlider _sendDelayedActions] + 110
 6   Foundation        0x01e39cea __NSFireDelayedPerform + 441
 7   CoreFoundation    0x02a00d43 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 19
 8   CoreFoundation    0x02a02384 __CFRunLoopDoTimer + 1364
 9   CoreFoundation    0x0295ed09 __CFRunLoopRun + 1817
 10  CoreFoundation    0x0295e280 CFRunLoopRunSpecific + 208
 11  CoreFoundation    0x0295e1a1 CFRunLoopRunInMode + 97
 12  GraphicsServices  0x02c6a2c8 GSEventRunModal + 217
 13  GraphicsServices  0x02c6a38d GSEventRun + 115
 14  UIKit             0x000e0b58 UIApplicationMain + 1160
 15  SampleApp         0x0000203c main + 102
 16  SampleApp         0x00001fcd start + 53


おお、これは便利。前からこういうのが欲しかった。
コールスタックの内容はデバッガを使えば確認できるけれど NSLogだとお手軽に使える。

UIApplicationDelegate のマルチタスキング関連メソッド調査 [3] Notification

2010年9月2日木曜日 | Published in | 0 コメント

このエントリーをはてなブックマークに追加

Notification についてもざっと確認した(マルチアプリのみ)。
Loading…

結果は UIApplicationDelegate と同じ。
(それだけ)


以下、検証コード抜粋。

application:didFinishLaunchingWithOptions: にて NSNotificationCenterへ登録。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    
    // Override point for customization after application launch.
 NSNotificationCenter* center = [NSNotificationCenter defaultCenter];

 [center addObserver:self
      selector:@selector(recievedNotification:)
       name:UIApplicationDidBecomeActiveNotification
     object:nil];
 
 [center addObserver:self
      selector:@selector(recievedNotification:)
       name:UIApplicationDidEnterBackgroundNotification
     object:nil];
 
 [center addObserver:self
      selector:@selector(recievedNotification:)
       name:UIApplicationDidReceiveMemoryWarningNotification
     object:nil];
 
 [center addObserver:self
      selector:@selector(recievedNotification:)
       name:UIApplicationWillEnterForegroundNotification
     object:nil];

 [center addObserver:self
      selector:@selector(recievedNotification:)
       name:UIApplicationWillResignActiveNotification
     object:nil];
 
 [center addObserver:self
      selector:@selector(recievedNotification:)
       name:UIApplicationWillTerminateNotification
     object:nil];
        :

-(void)recievedNotification:(NSNotification*)notification
{
 NSLog(@"%@", notification.name);
}


GitHub
UIApplicationNotification at 2010-09-02 from xcatsan's iOS-Sample-Code - GitHub

UIApplicationDelegate のマルチタスキング関連メソッド調査 [2]非マルチアプリのケース

2010年9月1日水曜日 | Published in | 0 コメント

このエントリーをはてなブックマークに追加

[前回] Cocoaの日々: UIApplicationDelegate のマルチタスキング関連メソッド調査

今回は UIApplicationExitsOnSuspend==YES のケース。条件等は前回を参照のこと。
以下、調査結果(非マルチのケース)


1. ホーム画面から起動


起動(ホームボタン)

application:didFinishLaunchingWithOptions:
applicationDidBecomeActive:(state=0)

その後、停止(ホームボタン)

applicationDidEnterBackground:(state=2)
applicationWillTerminate:(state=2)

その後、起動(ホームボタン)

application:didFinishLaunchingWithOptions:
applicationDidBecomeActive:(state=0)


2. Fast App Switch で他アプリへ切り替える


Fast App Switch 起動

applicationWillResignActive:(state=0)

他アプリへ切り替え

applicationDidEnterBackground:(state=2)
applicationWillTerminate:(state=2)

他アプリ起動中に Fast App Switchで起動

application:didFinishLaunchingWithOptions:
applicationDidBecomeActive:(state=0)

- - - -
基本的に起動と終了の繰り返し。

人気の投稿(過去 30日間)