Reveal調(diào)試UI利器

Reveal

Reveal是分析霹崎、調(diào)試iOS應(yīng)用UI的利器胯陋。

Reveal能夠在運行時調(diào)試和修改iOS應(yīng)用程序蕾各。它能連接到應(yīng)用程序扒磁,并允許開發(fā)者編輯各種用戶界面參數(shù),這反過來會立即反應(yīng)在程序的UI上式曲。就像用FireBug調(diào)試HTML頁面一樣妨托,在不需要重寫代碼、重新構(gòu)建和重新部署應(yīng)用程序的情況下就能夠調(diào)試和修改iOS用戶界面吝羞。

安裝Reveal

Reveal 下載地址:http://revealapp.com/download/

集成指南

集成Reveal無需添加任何代碼兰伤,無需引入任何頭文件。庫將會在應(yīng)用啟動時自動加載钧排,并在您的應(yīng)用內(nèi)部啟動必要的Reveal服務(wù)敦腔。

三種集成方式

靜態(tài)連接

將Reveal的靜態(tài)庫文件連接入應(yīng)用,是最簡單快捷地啟用Reveal檢視的方式恨溜。

警告: 不要將Reveal庫文件隨著正式應(yīng)用一起發(fā)布符衔。 下面的步驟將會展示如何通過構(gòu)建配置,而把Reveal靜態(tài)庫文件糟袁,僅連接到調(diào)試構(gòu)建的流程中判族。

  1. 在Xcode中打開您的iOS工程。

  2. 啟動Reveal并選擇Help → Show Reveal Library in Finder项戴,這將會打開Finder窗口形帮,并顯示一個名為iOS-Libraries的文件夾。

  3. Reveal.framework 文件拖入Xcode中的Project Navigator面板。

  4. 在下圖所顯示的Add to targets對話框中沃缘,選擇所有您希望與Reveal集成的target躯枢。可選步驟:選中Copy items if needed槐臀,將會把 Reveal.framework 拷貝到工程中——如果您這么做了锄蹂, 請記住,當(dāng)更新Reveal至新版本時水慨,也依照上述步驟再次更新此庫文件得糜。

  5. 點擊Finish。

  6. 選擇Build Settings標(biāo)簽晰洒,在Other Linker Flags的Debug配置項中加入如下配置朝抖。

     -ObjC -lz -framework Reveal
    
  7. 如果您使用的是Xcode 7, 請確認(rèn) Reveal.framework 所在的目錄在您的工程配置項 “Framework Search Paths” 中。具體的內(nèi)容看起來會像這樣谍珊。

    FRAMEWORK_SEARCH_PATHS = $(inherited) "$(SYSTEM_APPS_DIR)/Reveal.app/Contents/SharedSupport/iOS-Libraries"
    
  8. 在Xcode中治宣,構(gòu)建并運行您的應(yīng)用。如果應(yīng)用運行于真實設(shè)備之上砌滞,請確保此設(shè)備與正在運行Reveal的Mac機器侮邀,處于同一Wi-Fi網(wǎng)絡(luò)中。

    如果一切正常運行贝润,請切換到Reveal應(yīng)用绊茧,此時您的應(yīng)用應(yīng)會出現(xiàn)在應(yīng)用選擇器的下拉列表當(dāng)中。選中您的應(yīng)用打掘,確認(rèn)可以看到此時正在模擬器(或設(shè)備)中運行的應(yīng)用界面截圖华畏。

動態(tài)加載

動態(tài)加載允許iOS應(yīng)用在運行時,可以按需地加載第三方庫尊蚁。采用這種方式亡笑,庫文件無需連接入應(yīng)用的可執(zhí)行文件,而是被加入到了應(yīng)用Bundle中去横朋,從而在運行時能按需加載况芒。這種方式使得開發(fā)者可以在個人應(yīng)用中,完全自由地控制Reveal庫的加載叶撒,以及其服務(wù)的啟動與停止绝骚。

將Reveal加入您的Xcode工程,使得您團隊中的其他成員無需任何額外的配置祠够,就可以使用Reveal压汪。

警告: 永遠(yuǎn)不要將包含Reveal動態(tài)庫文件的應(yīng)用正式發(fā)布。Apple不允許將含有動態(tài)加載庫文件的iOS應(yīng)用發(fā)布到Apple商店中古瓤。

  1. 在Xcode中打開您的iOS工程止剖。

  2. 啟動Reveal并選擇Help → Show Reveal Library in Finder腺阳,這將會打開Finder窗口,并顯示一個名為iOS-Libraries的文件夾穿香。

  3. libReveal.dylib 文件拖入Xcode中的Project Navigator面板亭引。

  4. 在下圖所顯示的Add to targets對話框中,反選所有的target皮获。這確保了Xcode不會在編譯時連接動態(tài)庫文件焙蚓。可選步驟:選中Copy items if needed洒宝,將會把 libReveal.dylib 拷貝到工程中——如果您這么做了购公, 請記住,當(dāng)更新Reveal至新版本時雁歌,也依照上述步驟再次更新此庫文件宏浩。

  5. 點擊Finish。

  6. Copy Bundle Resources配置區(qū)域中靠瞎,加入libReveal.dylib比庄。

  7. Link Binary With Libraries配置項中:

    • ?如果已有l(wèi)ibReveal.dylib,請將其移除——不應(yīng)在編譯時連接dylib文件乏盐。
    • 如果下列系統(tǒng)框架與庫文件還不存在佳窑,請將他們加入:
      • libz.tdb
      • CFNetwork.framework
      • QuartzCore.framework
      • CoreGraphics.framework - Xcode一般默認(rèn)會在工程中包含此框架文件。
  8. 為了能在debugger之外丑勤,將庫文件動態(tài)地載入設(shè)備上的應(yīng)用华嘹,您需要在構(gòu)建過程中加入對libReveal.dylib文件的code sign吧趣。

    進(jìn)入target的Build Phases標(biāo)簽頁法竞,選擇Editor → Add Build Phase → Add Run Script菜單。在Run Script階段中加入以下內(nèi)容:

    set -e
    
     if [ -n "${CODE_SIGN_IDENTITY}" ]; then
         codesign -fs "${CODE_SIGN_IDENTITY}" "${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}/libReveal.dylib"
     fi
    
  9. 將下面的代碼加入到項目中合適的類文件中(例如您的UIApplicationDelegate)强挫,適當(dāng)修改使之滿足您的需要:

    Swift:

    // MARK: - Reveal
    
     func loadReveal() {
         if NSClassFromString("IBARevealLoader") == nil {
             let revealLibName = "libReveal" // or "libReveal-tvOS" for tvOS targets
             let revealLibExtension = "dylib"
             var error: String?
    
             if let dylibPath = NSBundle.mainBundle().pathForResource(revealLibName, ofType: revealLibExtension) {
                 print("Loading dynamic library \(dylibPath)")
    
                 let revealLib = dlopen(dylibPath, RTLD_NOW)
                 if revealLib == nil {
                     error = String(UTF8String: dlerror())
                 }
             } else {
                 error = "File not found."
             }
    
             if error != nil {
                 let alert = UIAlertController(title: "Reveal library could not be loaded",
                                             message: "\(revealLibName).\(revealLibExtension) failed to load with error: \(error!)",
                                      preferredStyle: .Alert)
                 alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
                 UIApplication.sharedApplication().windows.first?.rootViewController?.presentViewController(alert, animated: true, completion: nil)
             }
         }
     }
    

    Objective-C:

    #pragma mark - Reveal
    
     - (void)loadReveal
     {
         if (NSClassFromString(@"IBARevealLoader") == nil)
         {
             NSString *revealLibName = @"libReveal"; // or @"libReveal-tvOS" for tvOS targets
             NSString *revealLibExtension = @"dylib";
             NSString *error;
             NSString *dyLibPath = [[NSBundle mainBundle] pathForResource:revealLibName ofType:revealLibExtension];
    
             if (dyLibPath != nil)
             {
                 NSLog(@"Loading dynamic library: %@", dyLibPath);
                 void *revealLib = dlopen([dyLibPath cStringUsingEncoding:NSUTF8StringEncoding], RTLD_NOW);
    
                 if (revealLib == NULL)
                 {
                     error = [NSString stringWithUTF8String:dlerror()];
                 }
             }
             else
             {
                 error = @"File not found.";
             }
    
             if (error != nil)
             {
                 NSString *message = [NSString stringWithFormat:@"%@.%@ failed to load with error: %@", revealLibName, revealLibExtension, error];
                 UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Reveal library could not be loaded"
                                                                                message:message
                                                                         preferredStyle:UIAlertControllerStyleAlert];
                 [alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
                 [[[[[UIApplication sharedApplication] windows] firstObject] rootViewController] presentViewController:alert animated:YES completion:nil];
             }
         }
     }
    

    警告: 不要在發(fā)布(release)構(gòu)建中調(diào)用此方法岔霸,確保僅是在應(yīng)用的調(diào)試(debug)構(gòu)建中加載libReveal.dylib。

  10. 一個簡單的集成方式是俯渤,在-[UIApplicationDelegate applicationDidBecomeActive:]方法中調(diào)用上面聲明的- (void)loadReveal方法呆细,以確保Reveal庫盡早地被加載進(jìn)來。
    Swift:

    1. func applicationDidBecomeActive:(application: UIApplication) {
     self.loadReveal()
    }
    

    Objective-C:

    (void)applicationDidBecomeActive:(UIApplication *)application
    {
    [self loadReveal];
    }
    

    提示: 在-[UIApplicationDelegate applicationDidBecomeActive:]方法返回之前加載庫的一個好處是八匠,將會讓Reveal服務(wù)在應(yīng)用啟動的同時也自動啟動絮爷。

    如果您不希望如上述步驟自動啟動Reveal服務(wù),也可以以手動的方式來啟動梨树,例如通過一個Debug按鈕坑夯。在應(yīng)用啟動后,自己調(diào)用loadReveal方法抡四,然后再分發(fā)一個名為IBARevealRequestStart的NSNotification:
    Swift:

    func startReveal() {
        NSNotificationCenter.defaultCenter().postNotificationName("IBARevealRequestStart", object: nil)
    }
    

    Objective-C:

    - (void)startReveal
    {
        [[NSNotificationCenter defaultCenter] postNotificationName:@"IBARevealRequestStart" object:nil];
    }
    
  11. 在Xcode中柜蜈,構(gòu)建并運行您的應(yīng)用仗谆。如果一切正常運行,請切換到Reveal應(yīng)用淑履,此時您的應(yīng)用應(yīng)會出現(xiàn)在應(yīng)用選擇器的下拉列表當(dāng)中隶垮。選中您的應(yīng)用,確認(rèn)可以看到此時正在模擬器(或設(shè)備)中運行的應(yīng)用界面截圖秘噪。

CocoaPods

CocoaPods 是一款針對iOS與OSX項目的依賴管理系統(tǒng)狸吞。它大大簡化了以往Xcode工程里,對第三方庫的依賴管理與配置工作缆娃。

CocoaPods提供了Podspec用于將Reveal集成入您的項目捷绒。

警告: 不要將連接了Reveal庫文件的應(yīng)用用于正式發(fā)布。下面的指南描述了一種使用構(gòu)建配置來使Reveal靜態(tài)庫文件僅在調(diào)試構(gòu)建中連接的方式贯要。

此說明要求您在之前已經(jīng)在項目中配置好了CocoaPods暖侨,若不然,請先行配置Cocoapods崇渗。

  1. 將下面內(nèi)容加入你的Podfile中:

    pod 'Reveal-iOS-SDK', :configurations => ['Debug']
    
  2. 在項目的根目錄下執(zhí)行 pod install 命令(如果之前已經(jīng)在項目中使用了Cocoapods字逗,請執(zhí)行 pod update 命令)。

從您的Xcode項目中移除Reveal

根據(jù)您實際所選擇的Reveal集成方式宅广,請根據(jù)下述相關(guān)步驟來移除Reveal葫掉。

一旦庫文件成功的移除后,下面的內(nèi)容將不再會在您的應(yīng)用啟動時出現(xiàn)在Xcode控制臺:

INFO: Reveal Server started (Protocol Version X).

靜態(tài)連接

  1. 打開您的Xcode工程跟狱。
  2. Project Navigator刪除 Reveal.framework 的引用俭厚。
  3. 在Xcode的 Project Navigator中選中您的工程,對于每一個集成了Reveal得target驶臊,請選擇 Build Settings 標(biāo)簽頁挪挤,將下面內(nèi)容從 Debug 配置中的 Other Linked Flags 設(shè)置中移除:
    • -framework Reveal
    • -ObjC and -lz (刪除前請確認(rèn)此配置內(nèi)容僅是用于Reveal)。
  4. 搞定 - 運行應(yīng)用关翎,確認(rèn)Reveal沒有和應(yīng)用連接上扛门。

動態(tài)連接

  1. 打開您的Xcode工程。
  2. 從 Project Navigator 中刪除 libReveal.dylib 的引用纵寝。
  3. 在Xcode的 Project Navigator中選中您的工程论寨,對于每一個集成了Reveal得target,選擇 Build Phases 標(biāo)簽頁爽茴,如果下列庫文件僅供Reveal使用的話葬凳,請將它們從 Link Binary With Libraries 配置中移除:
    • libz.dylib
    • CFNetwork.framework
    • QuartzCore.framework
    • CoreGraphics.framework
  4. 將自定義的codesign內(nèi)容從 Build Phases 下的 Run Script 中刪除。
  5. loadReveal / startReveal 方法從您的代碼中刪除室奏。
  6. 搞定 - 運行應(yīng)用火焰,確認(rèn)Reveal沒有和應(yīng)用連接上。

CocoaPods

  1. 在您的Podfile文件中刪除下面這行內(nèi)容:

    pod 'Reveal-iOS-SDK', :configurations => ['Debug']
    
  2. 在項目的根目錄下執(zhí)行 pod update 命令窍奋。

  3. 如果您的 Podfile 中只有 Reveal-iOS-SDK 一個pod依賴荐健,請根據(jù)此說明酱畅,將CocoaPods從項目中完全移除。

  4. 搞定 - 運行應(yīng)用江场,確認(rèn)Reveal沒有和應(yīng)用連接上纺酸。

顯示效果

上圖是Reveal的運行界面,其界面主要分成3部分:

  • 左邊部分是整個界面的層級關(guān)系址否,在這里可以以樹形級層的方式來查看整個界面元素餐蔬。

  • 中間部分是一個可視化的查看區(qū)域,用戶可以在這里切換2D或3D的查看方式佑附,這里看到的也是程序運行的實時界面樊诺。

  • 右邊部邊是控件的詳細(xì)參數(shù)查看區(qū)域,當(dāng)我們選中某一個具體的控件時音同,右邊就可以顯示出該控件的具體的參數(shù)列表词爬。我們除了可以查看這些參數(shù)值是否正確外,還可以嘗試修改這些值权均。所有的修改都可以實時反應(yīng)到中間的實時預(yù)覽區(qū)域顿膨。

重要提示

  1. 不要將連接了Reveal庫文件的應(yīng)用正式發(fā)布。 Reveal的檢視機制叽赊,會將您應(yīng)用的許多內(nèi)部信息暴露出來恋沃,而這將很可能導(dǎo)致您的應(yīng)用被Apple審查團隊拒絕發(fā)布。Reveal的目的僅用于內(nèi)部開發(fā)與應(yīng)用調(diào)試必指。
  2. 當(dāng)iOS應(yīng)用進(jìn)入后臺后囊咏,Reveal服務(wù)將會自動停止。 當(dāng)應(yīng)用重新打開時塔橡,它又會自動啟動梅割。
  3. Reveal支持基于iOS 7及更新版本而編譯的應(yīng)用。 構(gòu)建配置中的iOS Deployment Target也必須是'iOS 7.0'或更新版本谱邪。 如果iOS版本太舊炮捧,您有可能會在構(gòu)建應(yīng)用過程中遇到連接錯誤庶诡。
  4. Reveal使用Bonjour協(xié)議來連接運行時的iOS應(yīng)用惦银。 如果您的iOS應(yīng)用是運行在真實的設(shè)備之上,那么此設(shè)備也需要處在同一個網(wǎng)絡(luò)之內(nèi)末誓,以便電腦上的Reveal應(yīng)用能夠與之連接扯俱。如果您在連接應(yīng)用時仍遇到問題,請先檢查防火墻和代理設(shè)置喇澡,以確保它們沒有阻礙通訊迅栅。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市晴玖,隨后出現(xiàn)的幾起案子读存,更是在濱河造成了極大的恐慌为流,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件让簿,死亡現(xiàn)場離奇詭異敬察,居然都是意外死亡,警方通過查閱死者的電腦和手機尔当,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進(jìn)店門莲祸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人椭迎,你說我怎么就攤上這事锐帜。” “怎么了畜号?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵缴阎,是天一觀的道長。 經(jīng)常有香客問我简软,道長药蜻,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任替饿,我火速辦了婚禮语泽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘视卢。我一直安慰自己踱卵,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布据过。 她就那樣靜靜地躺著惋砂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪绳锅。 梳的紋絲不亂的頭發(fā)上西饵,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天,我揣著相機與錄音鳞芙,去河邊找鬼眷柔。 笑死,一個胖子當(dāng)著我的面吹牛原朝,可吹牛的內(nèi)容都是我干的驯嘱。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼喳坠,長吁一口氣:“原來是場噩夢啊……” “哼鞠评!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起壕鹉,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤剃幌,失蹤者是張志新(化名)和其女友劉穎聋涨,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體负乡,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡牛郑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了敬鬓。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片淹朋。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖钉答,靈堂內(nèi)的尸體忽然破棺而出础芍,到底是詐尸還是另有隱情,我是刑警寧澤数尿,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布仑性,位于F島的核電站,受9級特大地震影響右蹦,放射性物質(zhì)發(fā)生泄漏诊杆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一何陆、第九天 我趴在偏房一處隱蔽的房頂上張望晨汹。 院中可真熱鬧,春花似錦贷盲、人聲如沸淘这。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽铝穷。三九已至,卻和暖如春佳魔,著一層夾襖步出監(jiān)牢的瞬間曙聂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工鞠鲜, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留宁脊,地道東北人。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓镊尺,卻偏偏與公主長得像朦佩,于是被迫代替她去往敵國和親并思。 傳聞我的和親對象是個殘疾皇子庐氮,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容