客戶(hù)端可以獲取當(dāng)前屏幕截圖并上傳到前臺(tái)顯示出來(lái),但前臺(tái)是如何知道屏幕上哪些元素是可以與用戶(hù)進(jìn)行交互的呢?這就需要客戶(hù)端在上傳當(dāng)前屏幕圖像時(shí),將當(dāng)前屏幕中的可繪制元素的一些關(guān)鍵信息一同上報(bào)。客戶(hù)端可以遍歷當(dāng)前屏幕上所有的可視化元素,然后讀取元素對(duì)象所有的屬性值,組織成一定的格式上報(bào)。
那么mixpanel是怎么做的呢?與上面的分析大致相同,不同之處在于mixpanel使用的一個(gè)配置文件來(lái)定義收集哪些對(duì)象的哪些屬性信息。這里給出具體的配置文件,供大家參考。在代碼中對(duì)這些以JSON格式下發(fā)的配置文件解析成各自的對(duì)象描述類(lèi),客戶(hù)端就可以按照這些描述類(lèi)配置的信息獲取對(duì)象的關(guān)鍵信息了。
配置解析

配置文件解析類(lèi)圖
從圖中我們大致能領(lǐng)略整個(gè)配置的解析過(guò)程。不過(guò)我覺(jué)得如果圖中所有的描述類(lèi)都從MPTypeDescription類(lèi)中派生的話會(huì)更完美一點(diǎn)。
對(duì)象序列化

序列化類(lèi)圖
整個(gè)過(guò)程是由MPApplicationStateSerializer對(duì)象發(fā)起的,從當(dāng)前屏幕最底層的元素window開(kāi)始序列化:
-(NSDictionary*)objectHierarchyForWindowAtIndex:(NSUInteger)index
{
UIWindow* window = [self windowAtIndex:index];
if(window){
return [serializer serializedObjectsWithRootObject:window];
}
}```
整個(gè)序列化過(guò)程的算法是,將對(duì)象加入到末訪問(wèn)隊(duì)列中,從末訪問(wèn)隊(duì)列中取一個(gè)元素訪問(wèn)并序列化保存到已訪問(wèn)隊(duì)列中,訪問(wèn)的過(guò)程中如果元素存在子元素,則將子元素也加入到末訪問(wèn)隊(duì)列中等待后續(xù)訪問(wèn),如此遞歸到所有元素都已訪問(wèn)并序列化。

## 屏幕圖像的獲取
在MPApplicationStateSerializer類(lèi)中有一下screenshotImageForWindowAtIndex:的方法用來(lái)獲取屏幕的UIImage對(duì)象,然后將image轉(zhuǎn)化成NSData對(duì)象后一并通過(guò)JSON格式直接上報(bào)。同時(shí)取NSData對(duì)象的MD5值,用于前臺(tái)判斷屏幕圖像是否發(fā)生變化進(jìn)而刷新瀏覽中的顯示信息。
## 序列化數(shù)據(jù)協(xié)議格式
使用該協(xié)議格式將序列化后的所有數(shù)據(jù)上報(bào)到服務(wù)器,由前臺(tái)負(fù)責(zé)解析并在瀏覽器中顯示出來(lái),這里給也一個(gè)[參考文件](http://ocuwifxvz.bkt.clouddn.com/snapshot.json)。