この記事はGunosy Advent Calendar 2017の16日目の記事です。
昨日は@yamarkzさんの【ビットコイン】ウォレットの概要とHDウォレットの仕組みでした。
こんにちは。グノシー開発部iOS担当の@hongmhoonです。
今日はiPhoneのホーム画面であるSpringBoard
をデバッグしてみたいと思います。
もちろん実機iPhoneは普通ではデバッグ出来ないので実機ではなくiPhoneのシミュレータで行います。
Xcodeとシミュレータ準備
ここでは現在(2017年12月)の最新版のXcode9.2とiPhone X(iOS11.2)を利用します。
念のためXcodeとシミュレータは両方とも一度終了してから新しく起動します。
開くプロジェクトは既存でも新規でも構いません。
始める前に起動デバイスがiPhone X
になっていることを確認します。
プロセスにアタッチ
通常の開発では大体Run[Cmd + R]
コマンドでアプリを実行してデバッグしていると思いますが、SpringBoard
は既に実行中なので
Debug -> Attatch to Process -> SpringBoard
を選択してSpringBoard
プロセスにアタッチします。
しばらく待ってデバッグバーにこのようにSpringBoard
と表示されるのを確認します。
これでSpringBoard
プロセスに無事アタッチできました。
デバッグ開始
デバッグのためにプロセスを一時停止する方法は色々ありますが、
今回はメニューからDebug -> View Debugging -> Capture View Hierachy
を選択するようにします。
しばらく待つとなんかそれっぽい画面が現れます。左側を見るとWindowが4つもあるのがわかります。
左側から各Windowをクリックしながら確認するとホーム画面のアイコンはSBHomeScreenWindow
で表示されているのがわかります。
もうちょっと触ってみるとSBIconController
でアイコンの情報があるのがわかりましたのでSBIconController
の情報を出力してみます。
今回はコンテキストメニューからPrint Description of SBIconController
選択します。
出力結果を見て見るとvisibleIconIdentifiers
に色々なアプリのIdentifierが見えます。Maps
やmobilesafari
などだいたいはそのままどんなアプリか推測できます。
com.apple.Bridge
などのパッと見わからないアプリは、こちらwhat-is-the-bundle-identifier-of-apples-default-applications-in-iosからWatchアプリであることがわかります。
Printing description of $32:
<SBIconController: 0x7ff896803600; orientation: UIInterfaceOrientationPortrait; isEditing: NO; model: <SBIconModel: 0x600002ad4190; store: <SBDefaultIconModelStore: 0x60000023caa0>; applicationDataSource: 0x7ff896803600; rootFolder: <SBRootFolderWithDock: 0x60400011a550, (null)>; visibleIconIdentifiers: {(
"com.apple.Maps",
"com.apple.mobilesafari",
"com.apple.DocumentsApp",
"com.apple.Health",
"com.apple.Bridge",
"com.apple.reminders",
"com.apple.Preferences",
"com.apple.news",
"com.apple.Passbook",
"com.apple.mobileslideshow",
"com.apple.MobileAddressBook",
"com.apple.MobileSMS",
"com.apple.mobilecal"
)}; ignoresIconsNotInIconState: NO; sortsIconsAlphabetically: NO>; rootFolderController: <SBRootFolderController: 0x7ff89a021000; folder: <SBRootFolderWithDock: 0x60400011a550, (null)>; folderView: <SBRootFolderView: 0x7ff89a045a00; folder: <SBRootFolderWithDock: 0x60400011a550, (null)>; editing: NO; scrolling: NO; orientation: UIInterfaceOrientationPortrait; currentPageIndex: 1; iconListViewCount: 2; statusBarHeight: 44.000000; isScalingViewBorrowed: NO; minusPageCount: 1; dockOffscreenProgressSettingClients: NSHashTable {
}
; pageState: icon>>>
オブジェクト調査開始
せっかくなのでSBIconController
のアドレス0x7ff896803600
から利用可能なオブジェクトのメソッドをすべて表示して見ます。
po [0x7ff896803600 _shortMethodDescription]
と入力して見ます。
*アドレス0x7ff896803600
は環境によって変わるので試す場合は自分の出力からの値を利用してください。
(lldb) po [0x7ff896803600 _shortMethodDescription]
<SBIconController: 0x7ff896803600>:
in SBIconController:
Class Methods:
+ (BOOL) _supportsPopovers; (0x101e70012)
+ (id) sharedInstance; (0x101e6229c)
+ (id) sharedInstanceIfExists; (0x101e62360)
Properties:
@property (readonly, nonatomic) BOOL canOpenFolders;
@property (readonly, nonatomic) BOOL canCloseFolders;
@property (retain, nonatomic) _UILegibilitySettings* legibilitySettings;
@property (nonatomic) BOOL hasRestrictedEnforcedLayout; (@synthesize hasRestrictedEnforcedLayout = _hasRestrictedEnforcedLayout;)
@property (nonatomic, getter=isUninstallingSystemAppsRestricted) BOOL uninstallingSystemAppsRestricted; (@synthesize uninstallingSystemAppsRestricted = _uninstallingSystemAppsRestricted;)
@property (retain, nonatomic) SBIconView* highlightedIconView; (@synthesize highlightedIconView = _highlightedIconView;)
...省略...
@property (readonly) unsigned long hash;
@property (readonly) Class superclass;
@property (readonly, copy) NSString* description;
@property (readonly, copy) NSString* debugDescription;
Instance Methods:
- (id) nestingViewController:(id)arg1 animationControllerForOperation:(long)arg2 onViewController:(id)arg3 animated:(BOOL)arg4; (0x101e73b40)
- (id) nestingViewController:(id)arg1 interactionControllerForAnimationController:(id)arg2; (0x101e7427e)
- (void) nestingViewController:(id)arg1 willPerformOperation:(long)arg2 onViewController:(id)arg3 withTransitionCoordinator:(id)arg4; (0x101e745c1)
- (void) handleReachabilityModeActivated; (0x101e7674a)
- (void) handleReachabilityModeDeactivated; (0x101e767ed)
...省略...
メソッド呼出
これでView Hierachy
からオブジェクトの変数やメソッドを探せるようになりましたので簡単なメソッド呼出をして見たいと思います。
アイコンのフォルダ名を狙って見ます。
色々クリックしてみるとアイコンのフォルダ名のビューはSBFolderTitleTextField
であることがわかりましたので先ほどと同じくコンテキストメニューからPrint Description of SBFolderTitleTextField
選択してみます。
出力結果を見て見るとSBFolderTitleTextField
はUITextField
のサブクラスでした。
Printing description of $92:
<SBFolderTitleTextField: 0x7ff89618f000; baseClass = UITextField; frame = (43 89; 288.667 56); text = 'Extras'; opaque = NO; gestureRecognizers = <NSArray: 0x60400084ea60>; layer = <CALayer: 0x604000829e40>>
ならsetText:
でフォルダ名を変更出来そうな気がするのでして見ます。
変更後反映のためにcontinue
でプロセスを再開します。
(lldb) po [0x7ff89618f000 setText:@"hmhv"]
0x000000010e60acc0
(lldb) continue
Process 5812 resuming
お!予想通りフォルダ名が変更されました!!
*フォルダ名を再表示させると元に戻ります。
まとめ
今日はiPhoneのホーム画面であるSpringBoard
をデバッグしてみました。この方法で同じくマップやsafariなどのお馴染みのアプリもデバッグが可能なので色々試して見てください。
ちなみに今まで使っていたデバッグコマンドの po
ってなんの略かわかりますか?
print object
でしょうというそこのあなた、正解は以下のコマンドで自分で確認して見てください。
(lldb) help po