built new Mac.

MacBook Air (Late 2010)からMacBook Pro 13" Retinaに移行した際のメモ。

■Boot

  • 起動は普通に日本語で適当に。

  • ■AppStore

    AppStoreから必要なものを再DL
  • Xcode
  • Evernote
  • Twitter for Mac
  • Alfred
  • Go2Shell
  • Cloud
  • Skitch
  • The Unarchiver
  • CCleaner
  • Dash
  • ■Document for Dash

    Xcodeを入れたら、DashのためにiOSのドキュメントをDL。ついでにCommand Line toolsも。

    システム環境設定

    ■Dock

  • サイズと拡大率を適当に調整して自動非表示ON
  • ■Mission Control

  • ホットコーナーで右上でディスプレイのスリープ
  • ■Firewall

  • とりあえずON
  • ■Spotlight

  • 色々はずしておく
  • ■Keyboard

  • 「すべてのコントロール」に変更
  • キーリピート最速、最短認識
  • 標準ファンクションキーにチェック
  • ■Trackpad

  • 軌道最速
  • Mission ControlとExposeをチェックオフ(BTTと干渉するので)
  • フルスクリーンアプリ間移動は4本指に変更
  • ■共有

  • host名変えとく
  • ■アクセシビリティ->マウスとトラックパッド

  • トラックパッドオプション->ドラッグ有効、ドラッグロックあり、最速スクロール

  • App from web

  • Firefox
  • Dropbox
  • SugarSync
  • 1Password
  • VLC
  • Insomnia
  • BetterTouchTool
  • GoogleChrome
  • Google日本語入力
  • TuneTEXT
  • Witch

  • Music

  • ~/Musicを固めてAirDropで持ってくるか、iTunesホームシェアリングでコピー

  • 開発環境

  • githubから自分のdotfilesをclone. vim-plugin、symlink等設定
  • homebrewからdpkg入れる
  • theos installシェルスクリプトでtheosインストール
  • tweakのtheosへのsymlinkが外れているのを修正

  • 設定

    ■BetterTouchTool

    Global
  • 4FingerSwipeUp/Down : ShowDesktop
  • 3FingerSwipeUp/Down : MissionControl
  • CornerClickBottomRight : RightClick
  • Terminal
  • 3FingerSwipeLeft : Cmd+Shift+[
  • 3FingerSwipeRight : Cmd+Shift+]
  • ■Witch

  • [Behavior] Show list : right away
  • [Behavior] Show←のチェックは外す
  • [Appearance] 42pt, Show : applicationIcons

  • これで大体完了。

    FakeClockUp v0.7.1-1

    ここ最近tsSpeed Aをオープンソース実装する事を目指してFakeClockUpをバージョンアップしてきてv0.7.1-1で達成できました。バイナリ・ソースコードともにgithubにあります。ライセンスは踏襲してApache License 2.0です。

    ■実装の雑感

    スライダーの値はfloat型でしか得られないので、スライダーの値をListの値に完全に合わせてあげなければ設定が同期しているようにならないのですが、ここで他のSpecifierの値を設定するにはobjectを引数とするメソッドを使用するので、floatもしくはdoubleからオブジェクトへ変換する際にNSNumberを使って0.100000000の値を[NSNumber numberWithDouble:0.100000000];してみると実際の値は0.099999998753みたいな値になってしまい同期がとれませんでした。なので、最終的にはNSStringとして保存する形になりました。詳しくはソースで。

    Sleipnizerで使っているAllAroundPullViewを公開しました。

    タイトル通り、Sleipnizerで使っているPull-To-Gestureの部分のコードをgithubで公開しました。特徴はSleipnizerで使えるように4方向に対応している事です。branchのsleipnizerがまさに使ってる状態です。

    https://github.com/r-plus/AllAroundPullView

    使い方の詳細はgithubのREADMEを参照。

    chpwnのPullToRefreshViewを元に以下な感じの代物です。

  • 色々と微妙な実装だったので修正(大分不親切な実装だった)
  • 4方向に対応
  • コード実行部分をdelegateからBlocksに変更
  • LabelとLastRefreshDateを削除
  • XcodeのDemoプロジェクトの追加
  • tweakで使えるようにARC非対応!非対応!
  • kCFCoreFoundationVersionNumberのススメ

    iOSのバージョンを判定するのには二通り程あって、UIDeviceから取得する方法

    float iOSVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
    と、kCFCoreFoundationVersionNumberを使うやり方があります。
    kCFCoreFoundationVersionNumber >= 550.52 //550.52はiOS 4.2の値

    ちなみにfloatValue使うと小数点2個は取れないので5.1.1は5.100000になります。kCFCoreFoundationVersionNumberも3項目のバージョンでの値に変更はないため、3項目までちゃんと取る場合はNSNumericSearchできちんと比較する必要があります。

    で、tweakのバージョン判定では2項目までで十分な事が多いのでkCF~の方がオススメです。うっかりspringboardが対象のtweakのconstructorでUIDevice使うと危険なので。UIDeviceを使ってはいませんが、iOS5が出た当初に発現していた画面1/4問題は、例えばLastAppでは以下のバージョン判定の1行が原因で起こっていました。

    isFirmware3x_ = (class_getInstanceMethod(objc_getClass("SBApplication"), @selector(pid)) != NULL);
    これを以下に書き換えることで対処したと思われます。
    isFormware3x_ = (kCFCoreFoundationVersionNumber < 550.32) ? YES : NO; // 550.32はiOS 4.0の数字

    新OSが出た際の確認方法は/System/Library/Frameworks/CoreFoundation.framework/Info.plistのCFBundleVersionから確認できます。iOS5.1.xは690.10ですね。

    2.0からの番号はこのあたりを参考に。chpwn / IconSupport - Firmware.h

    What is Tweak?



    ■What is Tweak?

    「CydiaでよくダウンロードするTweakとは何なのか?」について割りと詳しく解説してみようと思う。

    様々な便利な機能の追加や、細かい変更をOSに施すTweakは単語であるTweakの意味「ちょっとした調整」から来ている。ソフトウェアの既存動作にちょっとした調整を加える目的のソフトウェアをさす。

    では好みの動作をさせるにはどうしたらいいか。
    端的に言えばある処理をフックして好みの処理に置き換える事で実現出来る。

    フックを考えるにあたってまず、そのソフトウェアの動作を考えよう。
    iPhoneひいてはOS Xのソフトウェアは専らObjective-Cで記述されている。
    Objective-Cは非常に動的な言語で、コンパイル時点であまり警告・エラーを出さず実行時にうまいこと動けばOKって感じの言語だ。

    オブジェクト指向言語であり、クラスとメソッドとインスタンス変数があってカプセル化されているように見えるが、C言語が皮をかぶっているだけで中でランタイムがゴリゴリ動いてる印象だ。

    メソッドもC関数に皮を数枚かぶせた感じの実装で、実態はIMP型という関数ポインタだ。

    更にランタイムが非常に強力で、カプセル化されていながら、見ようと思えば何でも見れるようになっていて実にフックしやすい言語なんだ。

    フックの仕方には何種類か方法があって、木下さんの連載を参考にすると
    あたりが挙げられる。詳しくは連載の方が面白いのでそちらを見ていただくとして、簡単で便利なのはIMPの入れ替えだ。
    IMP変数を取得するための関数もランタイムで提供されているため、実に簡単にフックが行える。

    ■例を見てみよう!

    - (BOOL)shouldShowDictationKey;というインスタンスメソッドがUIKeyboardLayoutStarクラスに存在する。これは音声入力キーを表示すべきかどうかYESかNO(BOOL値)で返すメソッドだ。
    iOSの音声入力はSiriが可能な言語と今のところ同じであるので、使用中のキーボードがそれに該当するかどうかを判定してYESかNOを返していると想像がつくと思う。

    このメソッドを書き換えて常にYESやNOを返す処理に変えてしまえば、あのマイクキーが常に出るようになったり、常に表示されなくなる事も想像がつくだろう。 このメソッドをフックするには以下のようなコードで実現できる。
    IMP old, new;
    old = class_getMethodImplementation([UIKeyboardLayoutStar class], @selector(shouldShowDictationKey));
    new = class_getMethodImplementation([UIKeyboardLayoutStar class], @selector(new_shouldShowDictationKey));
    
    IMP tmp;
    tmp = old;
    old = new;
    new = tmp;
    
    オリジナルのメソッドを使う気がなければ最後のところは
    old = new;
    だけで事足りてしまう。 また、method_exchangeImplementationsなんて素敵な関数もあるのでこうも書ける。
    Method old, new;
    old = class_getInstanceMethod([UIKeyboardLayoutStar class], @selector(shouldShowDictationKey));
    new = class_getInstanceMethod([UIKeyboardLayoutStar class], @selector(new_shouldShowDictationKey));
    
    method_exchangeImplementations(old, new);
    いずれにせよ、これらの処理を行えば以後OSやアプリケーションがshouldShowDIctationKeyメソッドを呼び出すと、実際に処理が走るコードは自らが書いたnew_shouldShowDictationKeyメソッドのもととなる。 ちなみにnew_shouldShowDictationKeyは追加しなければならないので、class_addMethod関数で追加できる。
    static BOOL replaced_UIKeyboardLayoutStar_shouldShowDictationKey(UIKeyboardLayoutStar *self, SEL _cmd) { return NO; }
    
    class_addMethod([UIKeyboardLayoutStar class],
        @selector(new_shouldShowDictationKey),
        &replaced_UIKeyboardLayoutStar_shouldShowDictationKey,
        "c@:");
    
    メソッドの実装であるIMPを上書きするだけでも書き方は色々ある。
    Method method = class_getMethodImplementation([UIKeyboardLayoutStar class], @selector(shouldShowDictationKey));
    static BOOL replaced_UIKeyboardLayoutStar_shouldShowDictationKey(UIKeyboardLayoutStar *self, SEL _cmd) { return NO; }
    
    method_setImplementation(method, &replaced_UIKeyboardLayoutStar_shouldShowDictationKey);
    
    さて、これらの処理を適当な関数にまとめて、その関数を呼び出せば晴れてフックが完了するが、元々は存在しない関数だ。一体どうやって呼べばいいのか。
    そもそもこのコードを任意のタイミングで読みこませる(ロード)にはどうしたらいいのか。

    まず、動的なコードのロードはライブラリが同様の形態を持っているため、これを読み込むための環境が配備されている。OS XのサブセットであるiOSではdyld(Linuxならld-linux.so)によって読み込まれる.dylib形式(Linuxで言えば.so、Windowsなら.dll)にコンパイルしてdyldに読み込んでもらえばいい。

    次に関数の呼び出しだがアプリケーション側が呼んでくれるはずもないので、ロードされたタイミングで実行する関数をdyldに指定するオプションがある。これはgccの-initオプションの引数に関数名を記述すればいい。このオプションはDarwin linker(dyldのことだ)に引き渡される。man dyldでマニュアルを読むとこのオプションで指定された関数はdyldによって実行される事が書いてある。
    そこには__attribute__((constructor))が指定されたものも実行する事が記述されている。

    これらをまとめると、このTweakは以下のようなコードになる。

    このコードを動的にロードできるようdylib形式でコンパイルしたファイルがTweakそのものだ。

    この例だとメソッドの置換ではなく上書きにしたため、わりと短いコードですんでいるが、置換するとなると行うべき処理は多くなっていき、フックするメソッドが増えていくととても長いコードになっていく。そこで、このランタイムによる実装の置き換えを便利な関数でまとめてくれたライブラリを提供してくれるパッケージがCydiaにはある。そう、MobileSubstrateだ。

    ■MobileSubstrate

    MobileSubstrateの提供する関数はメソッドの置換や関数の置換、インスタンス変数の取得を行える関数を提供してくれている。
    では上記のコードをMobileSubstrateの一般的な関数を使用した形にすると、以下の様になる。

    種々のTweakが一様にMobileSubstrateをパッケージの依存関係に指定しているのは、MobileSubstrateが提供する関数を使用しているのもあるが、他にも重要な機能をMobileSubstrateは担っている。 ざっと以下のような構成だ。
    • MSHook系関数を提供するライブラリlibsubstrate.dylib
    • TweakをロードするSubstrateLoader.dylib
    • plistによるTweakのロードを制御(SubstrateLoader)
    • DYLD_INSERT_LIBRARIES環境変数へのMobileLoader.dylib(MobileSubstrate->SubstrateInjection->SubstrateBootstrap->SubstrateLoader)の追加
    • DYLD_INSERT_LIBRARIESを元に戻すMobileSafety
    この中で、TweakをロードするSubstrateLoaderが最重要機能といってもいいだろう。
    これはDynamicLibrariesディレクトリ以下のdylibを同名のplistの内容からロードの可否を判定してロードしてくれる。特定のアプリケーションにのみフックを適応させたい場合、このplistに条件を記述しておくことでコード本体にそのif文をかかずにすむようになっている。これがないと各Tweakは自分で自分のコードをロードする為のコードをかかなくてはならなくなってしまう。

    TweakをロードするのがSubstrateLoaderなら、SubstrateLoaderはどのようにロードされているのだろうか。SubstrateLoaderだって勝手に書かれた関数でしかないのだ。これにはDYLD_INSERT_LIBRARIESという環境変数へdylibを指定する事でdyldがロードするdylibの一つに加える事で実現している。

    DYLD_INSERT_LIBRARIESはLinuxでいうところのLD_PRELOADに非常によく似ていて、テストのために一時的に使用するライブラリのバージョンを違うものを指定したい時などに使われるものだ。LD_PRELOADを使ったフックについてはこちらのページ(LD_PRELOADを使ったテスト(C言語編))が非常にわかりやすく、行なっている内容もiOSのTweakと非常に似ている。そんなに長くないので是非読んでみてほしい。

    現在のMobileSubstrateはMobileSubstrate.dylibをDYLD_INSERT_LIBRARIESに追加している。/Library/MobileSubstrate/MobileSubstrate.dylibは/Library/Framework/CydiaSubstrate.framework/Libraries/SubstrateInjection.dylibへのシンボリックリンクとなっていて、SubstrateInjection.dylibは同ディレクトリのSubstrateBootstrap.dylibへのシンボリックリンクとなっている。
    SubstrateBootstrapからSubstrateLoader.dylibが読み込まれ、各種Tweakが読み込まれる流れだ。

    最後にMobileSafetyについて。SpringboardをクラッシュさせるTweakをインストールしてしまった場合、無限にRespringする事態におちいるのを防ぐためにTweakの導火線であるSubstrateLoader.dylibをロードするDYLD_INSERT_LIBRARIES環境変数を元の状態に戻した上でSpringboardを起動する役目を担っている。これが俗にいうSafe Modeだ。Tweakのロードを行わないだけなので、Cydiaからインストールしたフックを行わないアプリケーション(iFileとか)は普通に起動できる。SpringboardのクラッシュまでならMobileSafetyで対応できますが、Rebootループになるようなものには無力なので、最新のMobileSubstrateでは音量アップボタンを押しながら起動する事でTweakはおろかMobileSafetyもロードせずに起動できるようになりました。この場合もやっぱりiFileとかは動かせます。

    ちなみにOS XではSIMBLというLoaderが有名だ。MSHook系の関数を使用する前のようなコードを書く事でOS X向けのTweakも作成できる。

    ■theos

    最後にtheosについて。theosはiOS向けのMakefileプラットフォームで、長ったらしいMakefileを非常に簡素化できます。また、詳細は過去の記事を参照として割愛しますが、Tweak向けにマクロを用意してあり、直感的に記述できるようになります。
    上記の例示コードでいくとtheosを使用するとたった3行で記述できてしまいます。簡単だね!:)

    %hook UIKeyboardLayoutStar
    - (BOOL)shouldShowDictationKey { return NO; }
    %end

    ■終わりに、Jailbreak developerが増える事を願って。

    iOSのTweakのソースコードの多くはgithubで公開されています。
    記事上部で長々と書いたコードもtheosを使えば簡単に書けますので、「ここの動きが気に食わない」と感じるところがあれば、是非チャレンジしてみてはどうでしょうか。私も最初は大学でのC言語の授業(ポインタぐらいまで)程度の知識からスタートしましたので、そんなに難しくはないと思います。
    何より自分の作ったものが動くというのは楽しいものですよ?