急速收藏:4套iOS SDK的H5打通方案
在介紹 iOS SDK 的 H5 打通方案之前,我們先了解一下什么是 App 與 H5 打通。
所謂 “打通”,是指 H5 集成 JavaScript 數據采集 SDK 后,H5 觸發的事件不是直接同步給服務端,而是先發給 App 端的數據采集 SDK,經 App 端數據采集 SDK 二次加工處理后緩存到本地,再經過合適的上傳策略同步到服務端。
二、APP?與 H5?打通的原因
關于 App 與 H5 打通的原因,我們主要是從以下幾個角度考慮:
2.1數據丟失率
在業界,App 端采集數據的丟失率一般在 1% 左右,而 H5 采集數據的丟失率一般在 5% 左右(主要是因為緩存、網絡或切換頁面等原因)。
因此,如果 App 與 H5 打通,H5 觸發的所有事件都可以先發給 App 端數據采集 SDK,經過 App 端二次加工處理后存入本地緩存,在符合特定策略之后再進行數據同步,即可把數據丟失率由 5% 降到 1% 左右。
2.2?數據準確性
眾所周知,H5 無法直接獲取設備相關的信息,只能通過解析 UserAgent 值獲取到有限的信息。而解析 UserAgent 值,至少會面臨以下兩個問題:
(1)有些信息通過解析 UserAgent 值根本獲取不到,比如應用程序的版本號、設備具體型號等;
(2)有些信息通過解析 UserAgent 值可以獲取到,但內容可能不正確。
如果 App 與 H5 打通,由 App 端數據采集 SDK 補充這些信息,即可確保事件信息的準確性和完整性。
2.3 用戶標識
如果用戶在 App 端注冊或登錄之前使用我們的產品,我們一般都是使用匿名 ID 來標識用戶。而 App 與 H5 標識匿名用戶的規則不一樣(iOS 一般使用 IDFA 或 IDFV,H5 一般使用 Cookie),從而就會導致一個用戶使用了我們的產品,結果產生了兩個匿名用戶。如果 App 與 H5 打通,就可以將兩個匿名 ID 做歸一化處理(以 App 端匿名 ID 為準)。.4
2.4 基礎功能
基于 App 與 H5 打通,可以實現諸如 App 內嵌 H5 可視化全埋點、App 內嵌 H5 彈框等更加高級的功能。
介紹完打通的原因之后,我們來看下 App 與 H5 如何進行打通。
三、打通方案演進
關于 App 與 H5 的打通,曾經一直是我們的一個痛點,為此我們也做了持續地探索和迭代。在這個過程中我們踩了很多坑,也積累了一些經驗,現在將按照方案演進的順序為大家一一介紹這幾種方式,并分析其背景、實現和優缺點。
方案一
背景和原理
iOS SDK 從 v1.6.8 版本開始支持 App 與 H5 打通,也就是打通方案的原始版本。
眾所周知,在實際開發中,一個技術方案的使用,都是為了解決某些問題。在早期的事件分析中,H5 的匿名 ID(一般使用 Cookie)經常變化,并且與 App 端(iOS 一般使用 IDFA 或 IDFV)不同。因此,導致一個 App 用戶在內嵌 H5 頁面的行為序列無法和原生頁面的行為聯系起來,為業務分析造成很大困擾。但是,如果將 App 端的匿名 ID 傳給 H5,就能保證 App 內嵌 H5 頁面使用的匿名 ID 和原生頁面一致,從而解決上述問題。
原理:
在 WebView 加載 H5 頁面完成后,iOS SDK 調用 JS 方法將匿名 ID 傳給 JS SDK,JS SDK 采集的埋點數據就可以使用 App 的匿名 ID,從而使得 App 進入 H5 頁面前后的用戶行為序列準確關聯。主要流程如圖 3-1 所示:
具體實現
具體實現主要分為下面幾個步驟:
(1)從圖 3-1 的打通方案流程可以知道,為了保證 JS SDK 已經加載完成,iOS SDK 需要在 H5 頁面加載完成后才能調用 JS 方法傳值。那么監聽 H5 頁面加載完成的時機,便成了打通的關鍵。
對于 UIWebView 而言,我們知道從 UIWebViewDelegate 的代理方法中可以獲取 UIWebView 加載 H5 頁面的進度,UIWebViewDelegate 的代理方法如下:
因此,我們在 UIWebView 的 H5 頁面加載完成調用 JS 方法,只需要實現 - webViewDidFinishLoad: 方法即可,如下所示:
UIWebView
對于 WKWebView 而言,查閱 Apple 的 WKWebView 相關 API 文檔沒有合適的代理方法去監聽 H5 頁面加載完成,不過發現了 loading 這個屬性,說明如下:
loading 屬性表示當前頁面是否正在加載,如果 loading = NO(即頁面不再加載了),表示 H5 頁面已經加載完成。因此,我們使用 KVO 監聽 loading 的屬性變化,就可以知道 WKWebView 加載 H5 頁面是否完成,具體實現如下所示:
WKWebView
(2)監聽 H5 頁面加載完成后,即表示 JS SDK 已經準備就緒。此時使用 WebView 調用 JS 方法,將 App 端使用的匿名 ID 傳給 JS SDK 即可,具體實現如下所示:
(3)JS SDK 后續采集的所有事件,都使用 iOS SDK 傳遞的匿名 ID 作為當前的用戶標識,具體實現如下所示:
優點:
-
由于 iOS SDK 不用處理 JS 端的數據,只需要傳少量信息到 JS 端,對 iOS SDK 的侵入較小;
-
可以同時兼容 UIWebView 和 WKWebView,滿足更多客戶需求。
缺點:
-
H5 產生的埋點數據,繼續由 JS SDK 上報到服務端,數據丟失的風險較大;
-
如果 WebView 加載完成,JS SDK 尚未加載,會導致打通失敗;
-
只要開啟打通,iOS SDK 就會把 App 端的匿名 ID 發給 JS SDK 。由于不會區分項目,這樣可能會導致數據錯亂。例如,客戶 A 的 App 內嵌了客戶 B 的 H5,可能導致客戶 B 的 H5 頁面使用了客戶 A 的匿名 ID,然后數據還是發到了客戶 B 的服務端,導致客戶 B 的用戶數據錯亂;
-
對于客戶來說打通的集成比較復雜。例如,如果客戶 App 項目中使用了多個 UIWebView 或 WKWebView ,需要在多處實現協議方法并調用 SDK 接口,接入的工作量會比較大。
3.2
方案二
背景和原理
為了減小加載 JS SDK 對客戶 H5 頁面的影響,后期 JS SDK 支持異步加載(即 H5 頁面加載完成后才開始加載 JS SDK)。這就導致一個問題:可能 WebView 加載完成時,JS SDK 尚未加載,此時方案一會打通失敗。為了解決這個問題,我們開發出了方案二。
因為 JS SDK 支持異步加載,所以 iOS SDK 不再依賴于 WebView 加載完成的狀態去判斷 JS SDK 是否加載完成。因此,方案二的關鍵問題是:iOS SDK 應該什么時機去調用 JS 的方法發送 App 端的數據,即 iOS SDK 怎么才能知道 JS SDK 加載完成?
原理:
在 JS SDK 加載完成并初始化后,發送一個 iframe(sensorsanalytics://getAppInfo)請求。然后在 App 的 WebView 的協議方法中攔截 H5 的頁面請求。如果出現 sensorsanalytics://getAppInfo 這個請求,即認為 JS SDK 加載完成。此時,調用 JS 的方法發送 App 端的數據,就能保證打通成功。主要流程如圖 3-2 所示:
具體實現
具體實現主要分為下面幾個步驟:
(1)JS SDK 初始化后發送 iframe 請求:
(2)iOS SDK 攔截請求。關于攔截 H5 頁面中的請求,在 UIWebView 和 WKWebView 實現略有不同,分別示例如下。
對于 UIWebView 攔截請求,需要實現 UIWebViewDelegate 中的如下代理方法:
對于 WKWebView 攔截請求,需要實現 WKNavigationDelegate 中的如下代理方法:
(3)判斷 sensorsanalytics://getAppInfo 請求,調用 JS 方法發送數據:
(4)JS SDK 采集的事件,都使用 iOS SDK 發送的匿名 ID 作為當前用戶的標識。
優點:
-
這種打通方案,由于 iOS SDK 不用處理 JS 端的數據,只需要傳少量信息到 JS,對 iOS SDK 的侵入較小;
-
可以同時兼容 UIWebView 和 WKWebView,滿足更多客戶需要;
-
支持 JS SDK 在 H5 頁面異步加載情況下的 App 與 H5 打通。
缺點:
-
H5 產生的埋點數據,繼續由 JS SDK 上報到服務端,數據丟失的風險較大;
-
只要開啟打通,JS SDK 就會把 App 的匿名 ID 發給 JS SDK 。由于不會區分項目,這樣可能會導致數據錯亂。例如,客戶 A 的 App 內嵌了客戶 B 的 H5,可能導致客戶 B 的 H5 頁面使用了客戶 A 的匿名 ID,然后數據還是發到了客戶 B 的服務端,導致客戶 B 的用戶數據錯亂;
-
對于客戶來說打通的集成比較復雜。例如,客戶 App 項目中使用了多個 UIWebView 或 WKWebView ,需要在多處實現協議方法并調用 SDK 接口,接入的工作量會比較大。
3.3
方案三
背景和原理
對于上述兩種方案,對功能影響較大的兩個問題是:
-
App 與 H5 打通后,App 發送匿名 ID 給 JS SDK 時不區分項目,對其他客戶數據造成較大影響;
-
H5 的埋點數據通過 JS SDK 上報,數據丟失的風險較大,并且部分數據無法采集。
為了解決上述兩個問題,我們對 App 與 H5 打通方案做了較大的修改,從而推出了方案三:
-
為了解決上述第一個問題,我們單獨增加了開啟打通的接口。如果客戶調用并開啟打通,iOS SDK 會修改當前 App 環境的 UA 值,拼接當前接入 SA 的 project(項目名) 和 host(域名)。這樣 JS SDK 可以判斷當前 H5 頁面是否需要打通,并且還可以校驗是否為同一個項目;
-
為了解決上述第二個問題,我們在 JS SDK 增加是否需要打通的判斷,如果需要打通就將 H5 產生的埋點數據發送到 App,由 iOS SDK 處理并緩存到本地,然后根據合適的策略上傳到服務端。
原理:
iOS SDK 修改 UA 來標記當前 App 集成神策的項目信息,JS SDK 根據 UA 值判斷是否需要打通。如果需要打通,JS SDK 將埋點數據發往 App,iOS SDK 解析并處理 JS SDK 端產生的埋點數據,再根據合適的策略上報到服務端。主要流程如圖 3-3 所示:
實現
具體實現主要分為下面幾個步驟:
(1) iOS SDK 開啟打通的接口,默認校驗當前數據接收地址中的項目。也就是將神策數據接收地址中的 host 和 project 寫入當前的 UA 環境,以便 JS SDK 解析:
(2)JS SDK 獲取當前環境的 UA 值,如果判斷當前環境為 App 內嵌 H5 并且開啟打通(UA 中包含 /sa-sdk-ios/sensors-verify),就會解析 UA 中的 host 和 project。如果根據 host 和 project 判斷當前 H5 與 App 集成的是同一個神策項目,則表示需要進行 App 與 H5 打通。此時 JS SDK 觸發 iframe 請求,發送埋點數據到 App :
JS SDK
(3) iOS SDK 攔截 WebView 請求,解析 JS 埋點數據并進行處理和緩存(此處以 UIWebView 的實現為例,關于 WKWebView 攔截請求的方案,上文已有介紹,此處不再贅述):
WebView 中攔截請求
解析 JS SDK 觸發 iframe 請求中的 URL 參數,從而獲取 JS SDK 發送的埋點數據:
優點:
-
H5 產生的事件數據,iOS SDK 先經過了加工:使用 App 的匿名 ID,增加設備信息、網絡和運營商信息等,從而提高了數據采集的準確性和完整性,保證了匿名 ?ID 的一致,為后續的行為序列分析提供了可靠的數據基礎;
-
通過 iOS SDK 緩存并上報,很大程度上降低了數據丟失的風險;
-
JS SDK 解析 H5 環境的 UA 標識判斷是否打通,避免了 App ?使用其他客戶的 H5 可能存在的數據丟失或產生臟數據問題。
缺點:
-
對于每個 WebView,都需要在協議方法中調用接口攔截請求,如果一個項目有多個 WebView,集成工作相對繁瑣;
-
如果客戶項目禁用 UIWebView,WKWebView 目前只支持異步獲取 UA 再進行修改,可能會導致兩個問題:如果客戶也需要修改 UA,可能會導致打通失敗或者客戶修改 UA 失敗;如果 App 首頁加載 WKWebView,這個頁面的 H5 會打通失敗。
-
JS SDK 發送的 iframe 請求,在客戶 App 環境中,可能被誤判為非法請求并進行攔截,導致打通失敗。
3.4
方案四
背景和原理
隨著客戶數量的快速增加,越來越復雜的使用場景和客戶環境,給我們的 App 與 H5 打通方案帶來新的考驗。在某些復雜客戶環境中,一個 H5 頁面可能存在于多個不同的 App 項目(可能是正式項目與測試項目,或一個集團內的多個業務線)中,各個 App 使用的神策服務器地址可能不同,并且都需要進行打通,目前上述的幾種方案,都無法滿足。
同時,Apple 準備禁用 UIWebView[1],越來越多的 App 開始從 UIWebView 遷移到 WKWebView 。但是,我們的 App 與 H5 打通方案,在 WKWebView 打通中存在一些遺留問題,影響了客戶的使用體驗。
面對客戶訴求和 Apple 的新規定,我們的 App 與 H5 打通方案,也亟待再次進行優化。因此,第四版打通方案應運而生。
原理:
通過技術調研,我們發現在 iOS 的 WKWebView 中,Apple 在 js runtime 環境里事先注入了一個
window.webkit.messageHandlers.xxxx.postMessage() 方法,我們可以使用這個方法直接向 Native 層傳值。
基于這一原理,iOS 開發中 Native 與 H5 的交互可以使用全新的解決方案。iOS 已經將 window.webkit.messageHandlers 向 H5 共享了當前的 webkit 環境,只要在 WKWebView 的 configuration.userContentController 中注入實現 WKScriptMessageHandler 協議的對象(即 JSBridge),H5 端通過調用 postMessage() 方法,即可直接向 Native 發送消息。
為了減輕客戶開啟 App 與 H5 打通的接入成本,方案四使用動態 swizzle 技術 hook 了 WKWebView 加載 URL 的方法。在拿到當前 WKWebView 對象后自動注入 JSBridge,從而避免在每個 WebView 中單獨調用,提升 SDK 的集成體驗。
在復雜的客戶環境,針對不同校驗策略的訴求,方案四使用了白名單策略。JS SDK 提供了接口設置 serverURL 的白名單集合,只要 App 設置的 serverURL 包含在白名單中,則集成 JS SDK 的 H5 都可以打通成功,巧妙地兼容了同一個 H5 需要在不同 App 項目中進行打通的場景。
方案四的主要流程如圖 3-4 所示:
具體實現
具體實現主要分為下面幾個步驟:
(1)開啟打通后,自動執行 swizzle:
(2)WKWebView 加載 H5,調用?swizzle 的方法,注入了?SAScriptMessageHandler ?對象(JavaScriptBridge)到
ScriptMessageHandler:
(3) JS SDK 發送埋點數據:
(4)在 SAScriptMessageHandler 中接收 js 發送的埋點數據:
優點:
-
使用 WKWebView 的相關 API 實現,相對穩定可靠;
-
一個公司的多個 APP,可以通過配置 H5 白名單,實現不同 ServerURL 的 App 都能打通 H5;
-
如果開啟 App 與 H5 打通,只需要通過初始化配置開關設置即可,不需要對每個 WebView 重復調用,方便客戶集成。
缺點:
-
目前通過 swizzle 方案 hook 了 WKWebView 加載 H5 的方法,如果 swizzle 邏輯出現問題,可能導致 WKWebView 加載 H5 失敗(目前測試和使用過程中均未發現);
-
方案只支持 WKWebView 。
四、總結
經過艱難的摸索和持續的迭代后,iOS SDK 的 H5 打通方案目前趨于穩定。當然,目前的方案只是在當前環境的最優選擇。對于以后的業務變化和技術發展,我們可能會面臨新的挑戰和難題。如果等到那一天,我們能做的也是積極地迎接挑戰,再次投入攻關和調研,找到適合我們的選擇。
這個持續探索的過程,既是對方案的一次次革新,也是提高自我認知和積累技術的過程。一路走來,感慨良多,想起同事常說的一句話:“做難事,必有所得。”
參考文獻:
[1]ITMS-90809: Deprecated API Usage - Apple will stop accepting submissions of apps that use UIWebView APIs.https://developer.apple.com/forums/thread/122114
更多精彩,可關注公眾號:神策技術社區。
總結
以上是生活随笔為你收集整理的急速收藏:4套iOS SDK的H5打通方案的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 报名倒计时 | 挣脱流量束缚,社交电商的
- 下一篇: CEO 赠书 | 讲述创新背后不为人知的