Pages

Wednesday, November 21, 2012

Google Analytics SDK for iOS v2 (Beta)

最近在留意 Google Analytics SDK 版本更新時候,發現它的 2.0 Beta 已經 Release 了,當回到官方網站找相關技術文章,也有了新的文件說明。

Google Analytics SDK 要讓開發人員可以更容易的從他們的 App 上收集使用者互動參與的數據。透過 2.0 Beta 可以追蹤到:

  • 多少活躍的使用戶。
  • 在世界上哪些地方有在使用。
  • 追蹤觀察特定的 Features。
  • 付費與交易的追蹤。
  • App 的 Crash 現象。
  • 以及更多有用維度分析。

但是開始前要注意到準備事項:

  1. 要使用 iOS 4.0 以上 
  2. GA Mobile Apps iOS SDK v2
  3. 一個想要追蹤的 iOS App
  4. 一個全新的 Google Analytics 的 App property 及 Profile。而我也是沒注意到這段而發生了資料送到異次元的狀況,後來找了文件才發現。

值得注意比較過去 1.0 和現在 2.0 的差異:

全新的 App profiles reports 介面

這邊不再是使用過去 Web 收集的版面,而是專門 Mobile 的分析圖表介面,所以包含了一系列相關的數據收集分析表。當然也只有支援 GA SDK 2.0 以上。

Exception tracking

GA SDK 開始追蹤錯誤,使用這項可以收集 crashes 和些非導致毀壞的錯誤立外資訊。

而在開發者要注意是,過去使用 trackPageview: 變成 trackView:,關於電子商務交易現在獨立出來做統計。過去用 Custom variables 收集在 2.0 被取消掉,不再支援。所以如果有進階額外資訊要收集,就用別的更新的 method 來取代。

對於 Google Analytics 想要了解更多,可以參考我的其它相關 Tag GA 整理文章。

GA beta - App Overview

Flurry Analytics 為我們提供更好閱讀的使用數據

Flurry - Create A New App

Flurry 平台統計服務 提供了一套簡易上手、容易閱讀的統計分析工具,只要將我們的 App 裝設 Flurry SDK,即可收集使用者的整體使用數據,作為些分析與改善使用,而當好奇 Flurry 這套 Analytics 要不要收費以及他們家獲利收費方式,在 Quora 找得到這樣的討論 How does Flurry make money? 而 Flurry 的 CTO Sean Byrnes 為大家解答。主要是靠 AppCircle 和 AppSpot,而 Flurry Analytics 還是依舊免費。

Flurry Analytics 可以幫我們收集與分析很多有用的數據

1. Usage

有多少新的使用者、多少活躍使用者、說少使用的次數、使用的時間長度、使用密集度、追蹤使用者安裝後的還使用的情況、使用者回流數、使用該 App 版本紀錄、逛 App 頁數與次數統計。

2. Audience

了解年齡分佈、姓別、地理位置、語言

3. Events

Event 記錄總表、使用者使用事件的路徑圖、Funnels 漏斗分析、收集到 Event 的 Logs 記錄表。

4. Technical

使用者的裝置統計、電信業者、裝置作業系統版本號統計。

以上藉由 Client 端行動裝置 ,裝載著對應的 SDK 工具,即可將數據收集回來平台上,讓我們對於使用情形作後續改版參考依據。

Tuesday, November 20, 2012

Build Static Library in Xcode 4

Cocoa Touch Static Library

寫程式總是一直提醒自己要 DRY - Don't Repeat Yourself,上從 Class Name 到 Method Name 到寫程式的邏輯都要謹記在心。因為當重複撰寫一樣的邏輯,在維護上就會變成做重複事情,一來浪費自己的時間,二來如果自己疏忽會造成忘記要修改,三來也會造成一起開發夥伴的困擾。

伴隨著 Project 的開發,會發現有些程式是可以模組化,讓它獨立出來變成單一 Xcode Project,除了維持它核心功能外,還能產生 Static Library 讓需要用到它的 Project 可以引用。如此一來 Static LIbrary 也可以重複使用在更多更多的 Project 上。


在 Xcode 的 Project Template 可以輕鬆完成這樣的設定,
將整個 Project 包裝起來成為 *.a 檔案,如此搭配釋放出的 Header Files,Client 端只要看懂 Header Files 不用知道實做細節,也就可以使用。操作步驟:
  • 選擇 Cocoa Touch Static Library。
  • 在 Build Phases 加入 Copy Headers 步驟,將要 Release 的 Header Files 挑選出來,放置在 Public 區塊。 
  • 回到 Build Settings 找到 Packing > Public Headers Folder Path,這邊是告知在包裝時候會將 Headers Files 放置位置。 
  • 因為 Xcode project 建置好的位置路徑很深,如果每次路徑要走那麼遠取用檔案也很不方便,於是在 Build Phases 可以加入 Run Script,在裡面撰寫將檔案取出來放置在桌面上的 Scripts。


當以上設定完畢,程式碼撰寫完,跑 Build & Run 就可以將整個 Project 的程式包裝產生 Static Library 了。

Xcode Pro Tip Setting - Treat Warnings as Errors

Treat Warnings as Errors

寫 iOS App 為了不要產生討人厭又不好沒用的程式碼,像是當在撰寫 Code 時候,Xcode 就可以即時產生 warnings。當大家一起在寫程式時候,我們不希望在當 Xcode 跑編譯時候產生一堆 warnings 列在那邊一直在警告與嚇著似乎有潛在問題存在。

小撇步:在 Build Settings > Other Linker Flags 加入 -Weverything,在 Build Settings > Treat Warnings as Errors 設定為 Yes。

能得知這方法是我的夥伴跟我分享 nshipster.com 的 Inhibiting Warnings 學到的。現在有在寫的 Xcode Project 我都會啓動這樣的設定了。如此在每次 Xcode 編譯就會把警告顯示出來,直到修正好才能過關。

Wednesday, August 29, 2012

UIViewController purgeMemoryForReason and crashes in iOS App

測試 iPhone App 時候,最怕測出自己無法預料的問題。所謂無法預料的就是很難重製,但是它就這樣存在 App 上。而當我們用心就知道,一定有問題存在。當 App 用 Ad hoc 方式發佈出去,這些 App 都裝在夥伴們的 iPhone, iPad 上,當真正發生 Crash 了,真的會覺得很不安與莫名其妙不知道從何下手。

好的 Crash Report 平台 如 TestFlight, Crashlytics 等等。這些 Tool SDK 都還算好安裝,再利用它們在當 App Crash 後,
收集 Crash 的 Log 將它們送回平台上,再利用網頁的優勢來做統計,讓我們知道最後僅有線索記錄。

ISSUE UIKit-[UIViewController purgeMemoryForReason:]

終於收到問題的通知信件了,當收到這樣的標題再進去看內容,還真的讓人不解。因為現在手頭上開發的 App 已經採用 ARC (Automatic Reference Counting in Objective-C and Xcode) 的寫法了,所有的物件釋放時機都交給這個機制去運作,我都不用太擔心應該釋放時機點問題,怎麼會出現最後 Memory warning 才會出現狀況呢?

到網路上找尋大家經驗,在這則三則找到了問題主因:

主要問題所在,當 App 操作上難免會有記憶體上升,所以系統會發出低記憶體的警告 Notification。但是如果在 UIViewController 寫了 [[NSNotificationCenter defaultCenter] removeObserver:self] 如此一來會把 UIViewController 還要接收註冊的 Observer 也一帶 Release 掉,因此 UIViewController 就不會進入 didReceiveMemory,也跟著不會去釋放該要被釋放的物件,導致最後記憶體下不來,而最後整個 App 直接 Crash 收掉。


而會這樣寫法有兩個主因:
  1. 懶惰。
  2. 對於 NSNotificationCenter 了解深度不夠。

正確的寫法是像這樣 [[NSNotificationCenter defaultCenter] removeObserver:self name:NotificationName object:nil] 也就是自己註冊的 Observer 就一對一在 View 要被移除掉時候一起移除掉。這樣才不會將不屬於自己的 Observer 也被移除掉。

寫程式最怕的就是亂處理非屬於自己掌控自己建立的物件、指令,這樣整個邏輯都會亂掉。最佳寫法就是要低藕合,只處理屬於自己掌控的。對的寫法就不能偷懶。

Saturday, August 25, 2012

iOS App 自行評估上的五個重要指標

身為一個開發出 N 個 iOS App 的你,對於一個 App 的好壞是否有心中的定數呢?怎麼樣的 App 在問市以前就可以先讓自己及贊助者、團隊都滿意呢?希望推出的 App 是一問市就獲得五顆星的佳評,還是要到後面自己在從一兩顆星慢慢追趕自己理想的五顆星呢?

根據我們的經驗,會發現每個使用者在針對 App 作出 Review 的時候不外乎就圍繞在五個主題上去描述他使用的經驗。而這五個主題是我們每天在追求要更上一層樓的。


1. User Interface

有好的 App 界面設計需要兩種專長有經驗的人才在一起合作才可行。App Designer 針對現在開發中的 App 的畫面,透過自己的設計能力去規劃畫面上每個地方的細節。套用各種 Designer 在美化上的公式,例如標齊對正、字體大小掌握、圖片材質的設計。這邊需要非常細心、創意、巧思才能完成理想圖。另外一種專長則是懂得實作進來的 App Developer,他的角色需要將 Designer 的用心根據自己程式的經驗將它實作起來,並且活化它,讓原本很美的靜態 App 理想圖變成實際看到、摸到、感覺到的 App,這時候開始後面的修改於調整,很多設計不是一次就能定數的。

2. User Experience

同樣的功能,同樣的企劃相信交由不同的開發團隊設計出來的使用體驗絕對會不一樣。是否需要很多步驟才能完成操作、還是操作的過程很不順利,要使用者等待很久、或者在操作過程讓使用者覺得干擾過多,很難達到使用者心中想要操作的指令。好的 User Experience 要能在操作上即反應出使用者心中所想要、所期待下一秒會出現的結果。並且可以依序的操作下去。這方面除了用心得開發之外,也要搭配好的程式技術來做各方面進一步的調整。往往 User Experience 的改進是在 App 開發出樣貌後,開始要精進的。

3. Information Architecture

iOS App 的寸土寸金的畫面上,要擺上哪些資訊是個極大的任務,這個畫面的出現是否讓使用者看的覺得有用、資訊是否足夠、資訊是否過多過少、資訊的上到下是否都對使用者而言很有意義,是否會讓使用者迷路,不知道怎麼進行上一頁、下一頁的各種操作。Information Architecture 的用心在於一個 App 的畫面有幾個,這些畫面上的資訊呈現與彼此的關聯性。要追求的是讓使用者覺得這樣的資訊呈現剛剛好。

4. Quality

所謂的品質是達到我們所有想要提供給使用者的功能都能正常的操作,都能順利的完成。當 App 操作過程會 Crash、操作的過程等待過久、操作的過程因為某些特殊原因,且沒有處理好,而讓使用者的操作路線斷掉,上不去下不來的狀況。所以好的品質是要讓使用者不但能完成 App 提供的功能之外,還能操作的夠久到使用者自己自行離開關閉此 App。

5. Content, idea

回到最初的問題,我們為何要設計這個 App,希望讓使用者可以看到哪些功能、讀到哪些資訊、讓使用者可以解決他們生活上哪些問題。在最開頭的企劃上是否就走對了路。內容相當的重要,不希望當以上四點都做到了,但是最後使用者卻嘆了一口氣:“這個 App 好無聊噢!對我一點用處都沒有。” 所以 App 能跟使用者緊密關係是這個項目要努力與用心的地方。

最後

當我們 iOS App 開發團隊進行每天工作的時候,時常都在天人交戰的部分就是以上這些項目,這些項目都是關係著我們推出後的 App 會帶給使用者哪些體驗。而這些過程很多部分會互斥或者互補的。有互補的狀況當然是最好的,最讓人擔心就是互斥的部分。

當為了好的 Information Architecture 缺犧牲了 User Experience,那麼我們必須要停下來問自己,哪一個最重要,如果能解決 User Experience 而 Information Architecture 再用別種方式來解決是不是很好呢?

這五個項目都是我每天在問自己的問題,對於現在手頭上正在進行的 App ,他在各個項目拿到幾分了呢?我們應該要在 App 問市前,心中就已經有譜了。戰爭還沒開打前,勝負就已經揭曉,這才是身為資深專業的 iOS App PM, developer 及每一個成員該有的知識。

NSKeyedArchiver 讓 iOS App 方便儲存 Objects 的資料

在 iOS App 開發裡面,我們要儲存使用者的購物清單,而這些購物清單透過使用者在瀏覽的時候,將它們一一記錄下來,當隨後使用者要查看即可方便顯示出來。

我們會規劃 Objects 來封裝我們的各種值,這些 Object 在規劃上研究深入就要由 Domain Model 來分析了。但是還好我們的 iOS App 不會到這麼複雜,只要基本的切分清楚在使用上方便即可。而我們是否有方便的方式將這些物件儲存起來呢?

NSKeyedArchiver 可以幫我們做到,透過 archive 即可將整串從 Root Object 開始將裡面所有的 Object 儲存起來。而下次要使用的時候只要透過 unarchive 取出即可還原。


實作 NSCoding

我們有 PersonalShoppingList 這樣的 Object,而裡面有 Food 的 NSSet 和 FoodWithIngredient 的 NSDictionary,而要記得是在所有要存的 Object 都要實作 <NSCoding> 並且規劃寫 - (id)initWithCoder:(NSCoder *)aDecoder; 和 - (void)encodeWithCoder:(NSCoder *)aCoder。當然的,所有裡面會牽扯到的 Object 自己寫的都要這樣去實作。所以最後會看到自己要存的各種 Object 都會有寫好要存取的值。

儲存

回到 NSKeyedArchiver 去將 PersonalShopping 指定給 archivedDataWithRookObject。當取得 NSData 後,一起將要儲存的 Path 規劃好之後,即可將它 writeToFile 寫進檔案。

讀取

取出的時候是將 NSData 透過完整路經將檔案指定回來,再將 NSKeyedUnarchiver 的 unarchiveObjectWithData 還原回來,即可繼續使用了。

NSKeyedArchiver 對於 iOS App 有做好 Object 規劃方面,儲存和讀取方面變的很方便,只要實作了此功能,我們的任何資料即可隨時存取,相當的方便。

Sunday, August 12, 2012

挫敗的上一步

圖為 Edward In Action 所有
很多現象永遠跟你想的不一樣。不論是已經收集了滿滿線索、信心滿滿、問了所有有經驗的夥伴自己的做法,只為了證明自己沒有錯。但是問題就是這樣的攤在面前,告訴著當事人你,是的,他就是錯了,不論怎麼試還是錯了。

這個現象常常發生在我們 iOS App 開發上,每當信心滿滿的按下 Xcode 的 Build & Run,就是會去預期這一次在模擬器上開起來後的測試效果要如自己預期般的呈現,結果,很抱歉,就是沒有。請問該怎麼辦?

我最常解決這樣問題的方法是借鏡於實驗。實驗裡面有實驗組與對照組,實驗組是投入要觀察的項目,而對照組是用來對照出來的實驗結果。所以為什麼問題會發生,程式功能跑不出來。是否有成功的案例,他是怎麼做的。我們要將這兩者的所有影響要素一一條列出來,將一樣的部分在腦海中一一刪去,剩下不一樣的項目。例如根據不同的經驗是:
  1. 程式的撰寫方式有改變。
  2. 引用的元件套件版本的差異。
  3. 設定上的不同。
  4. 在某種多重參數、要素組合的條件下造成的錯誤。

在卡住過程我們是最容易急的,因為當時間一直一直過去,可是問題卻一直攤在面前。所以面對這種挫折感的時候,最需要的就是冷靜,唯有冷靜才能平心靜氣的來慢慢穩健的分析。回到上一次成功的情境,去想想看為什麼那樣下會成功,但是現在卻不一行。

很多時候,當問題卡住了,透過回到上一次成功的經驗,能帶給自己更多的信心,也才能在這過程中找出差異性。所以有時候我們想要急著前進三步遇到挫折時候,何不先退後一步,深呼吸一下呢!

Called the Shot 談每日工作生產力

圖片為 Edward in Action 所有
每當談到軟體預估,我就想到《人月神話》第八章〈預估〉[Calling the Shot] 的貝比魯斯。在 1932 年美國職棒世界大賽,全壘打王貝比魯斯在打擊前伸手指向中外野,接著隨即打出了一支全壘打。打擊前他做了預估,憑藉著自己的實力與精準度打擊出去,這就是著名的貝比魯斯的全壘打預告 (Babe Ruth's Called Shot)

每當上司、主管、業務任何非技術背景同仁會來跟我商討功能的複雜度,以及大約需要多久,這個時間就要根據自己的經驗與了解度來做分析了,這沒有標準的答案,因為中間牽扯到執行寫程式的人技術、用心程度、負責程度,再到軟體測試是否能符合功能的需求來作開發,更不用再提任何變動的因素,而被迫要做調整。這些事情只要是軟體開發,就一定會碰到。前輩以及書上經驗跟我們說,只有不斷的練習,了解自己、了解團隊才能越來越掌控所需要的時間。

Called the Shot 的精神我會將它融入到每天的工作。早上進入公司,開發團隊會做個簡單的溝通同步了解彼此在哪一個戰線上,而對於自己,就會訂下一個本日可以完成的大項目,或者本日可以完成的兩個以上小項目。以現在 iOS App 開發為例:
  • 某主題的 UITableViewController 開發,因為它是負責資訊列表的提供,所以會在本日將它所需要的資料串接,放入 UITableViewDataSource,最後再讓資料呈現在畫面上。而有兩個基本原則會一起伴隨開發的,重新整理與載入更多。一個是使用者會需要將現在畫面上的資料更新到最新,另外一個是使用者會一直瀏覽瀏覽需要更多後面的資料,而將這些資料載入畫面中。
  • 使用者登入 UIViewController 設計,它是負責讓使用者可以來登入,所以這部分要將它規劃出輸入欄位,例如 Email, password,而當使用者輸入過程可以做些輸入上驗證,送出到伺服器上作密碼驗證,再回來跟使用者表達是否登入成功與否。最後再將畫面收掉,並且讓整體的使用體驗是給使用者有登入後的感覺。
  • 整個 App 會共用的照片拍照上傳程式,這邊設計上會以方便給予照片物件集合,讓使用者在拍完照片或者挑選完照片,即可透過這隻程式來上傳,過程中表現出目前進度。最後處理上傳成功與失敗的狀況。

這些是作為每天開始工作前,去思索一遍,動筆前先動腦,敲鍵盤前先想過,在自己展開工作一天,要來完成每日小目標。

1. 有明確目標

透過這樣的思索,讓自己在一開始即可想完整體面貌,而當面貌越完整,即可知道自己手邊資料材料是否足夠,在接下來一天設定這樣目標達成的可行性提升。

2. 排除萬難

因為設定了這樣目標,所以在接下來的工作時段,就是要全心全意的來實作,任何的阻礙都會視為仇敵的方式來看待。任何的干擾包含:無關緊要的電話、無管緊要的 Email 、無關緊要的人過來你身旁找你講不相干的事情、任何突然會讓你被迫離開座位阻斷你前進的因素,這些能免就要免。

最後每天傍晚跟團隊夥伴做一天回顧,如果有順利的執行以上項目,在自己一天內能完成的目標,並且順利地達成,最後還可以展示給夥伴們看,因為預估而實踐做了哪些功能、哪些昨天沒有今天才出來,今天因為我的用心而完成的小任務。

當完成了當初自己的預估,除了可以讓夥伴們眼睛一亮之外,自己在每個重要的一天,又完成了一個小成就。

Sunday, July 22, 2012

從被挑選過程談個人競爭力


新款 MarBook Air 讓我更有效率
數一數工作經驗也開始滿五年了。近日參加了些新鮮人年輕朋友們的咖啡廳聚會,聽聽小自己幾歲的年輕朋友們談他們的夢想、熱情與對未來的期待。有位年輕的小朋友跟我聊一聊天,覺得我對於自己的未來很有想法,也把我當老大哥在稱讚,讓我想起了一個自己小時候的故事。

小時候因為家父要到美國華盛頓大學讀企管研究所,讓我們家有機會搬到西雅圖生活兩年,也因此讓我有機會可以在西雅圖市立國小讀小學三、四年級。還記得那天上學的午飯過後,我從學校餐廳走到操場,步向橄欖球草皮場地,看到同齡的白人、黑人們大家分隊彼此追逐打著有計分趣味橄欖球賽,當下我就非常想要加入一起玩。當那場結束後,進入到新的一場時,兩隊就要重新分隊。

兩位資深體格好的男生站出來擔任兩隊的隊長,所有球員一字排開站在球場旁,分別由隊長以公平、一個一個彼此球隊輪流挑選的方式來進行。當時站在隊伍裡面的我,短短幾分鐘,對於這一切的遊戲規則和挑選過程產生相當大的震撼與難忘。內心想到兩個問題:

1. 你是什麼理由讓這位隊長挑選你?

2. 你是在第幾輪被挑選中?你的競爭力在哪?


我印象我是被第四輪挑中,我也不太清楚他選我的原因了,大概是看我身材不會太瘦太矮,看起來會跑步接球的樣子吧!我想。

這個被按照公平客觀的一輪一輪挑選隊友的方式,造就往後我對於自我要求、自我一人練習的最大動力。

不管做什麼事情,當你的戰場決定了,剩下就是認真以赴,贏得這場勝利。

在職場上我相當期許自己有特戰部隊特徵,有專長競爭力、有被長官及隊友挑選我加入的理由與吸引力、附有正義、客觀、服從、忍耐、克苦耐勞等要點。不管專案是好的案子、慘的案子都能殺進殺出,獲得好佳績、完成該階段被賦予的任務。

所以每當累了、疲倦了,想要找回更上一層樓的動力時,何不問問自己,這是你要投入的戰場嗎?如果這是你要投入的戰場,你希望是第幾輪被長官、被客戶挑選中呢?你的競爭力是什麼?為什麼別人要給你機會。