iOS app與瀏覽器深度鏈接 DeeperLink

轉載 http://awhisper.github.io/2016/05/11/iOSBrowserDomainBridge/?utm_source=tuicool&utm_medium=referral

 

Update 2016.11.23

更新一個最新的方案,老文章裏面介紹的2個方案都不如這個易操作,唯一的問題是就看iOS10的覆蓋率了,覆蓋率不夠之前下文的設備指紋方案可以與這個方案互補

  • 只支持iOS10以上
  • 通過剪切板
  • 跨越瀏覽器app與宿主app,傳遞數據

clipboard.js

一個1w Star的js庫

因爲iOS10系統給js開放了API可以操作剪切板,因此直接使用這個庫,可以很方便的在任何App的webview(包含safari,微信,qq,百度框等)將數據存入剪切板

然後很方便的在其他任何app中,讀取出剪貼板的數據用於互通

這個方案在準確度上,成功率上,適用範圍上全面優於下文討論的設備指紋SafariViewController方案

忘掉SafariViewController方案吧,這個方案現在非常的坑

原因是,SFViewController的方案,Openurl事件會以各種方式被系統吞吃掉事件,duplicate等等,都會導致失敗率非常的高

Deeper Link 簡介

本文主要介紹,app跨域訪問app外部的瀏覽器的數據的方案,包括外部safari,或者QQ,微信,手百等外部app內的瀏覽器。

主要使用場景就是:

用戶在別的wap網頁上,產生了用戶行爲,用戶數據,但是還沒下載app,當用戶下載app後,打算直接在app內延續之前在wap上的行爲和數據的時候,就需要運用到跨越瀏覽器與app鴻溝的,互通方案。

簡單舉個例子就是:

用戶在微信瀏覽器裏,訪問某個頁面,感興趣並且登陸了,然後引導下載了app,等用戶下載完app後第一次打開,希望能自動就完成登陸,甚至同步下來一些剛纔用戶在wap頁面上操作的數據

如果能發生跨瀏覽器與app的互通,除了這個case之外,還可以有更多地自由發揮,設計出更加舒暢的用戶體驗

這就是 Deeper Link

想要實現這樣目前看有2個方案,各自都有弊端,都不是完美的,本文會詳細說明這兩個方案

  • 設備指紋唯一識別方案
  • iOSSafariCookie互通方案

設備指紋唯一識別方案

如果用戶在wap頁面,能通過某種方式識別到唯一的設備標識,當用戶離開去下載app,下載完成第一次打開app的時候,app能識別到一樣的設備標識,那麼就可以判斷第一次打開app的用戶,就是剛纔瀏覽wap網頁的用戶,這樣服務就可以把剛纔wap上操作的數據結果,通過網絡下發給app,從而讓app實現,還原剛纔wap的操作場景

方案流程

  • 用戶在wap網頁上產生了行爲,產生了用戶個人數據
  • wap網頁收集了一種能夠唯一標識設備的信息,並且發送給了服務器
  • app安裝完畢後第一次運行,也去通過app嘗試收集唯一標識設備的信息,並且發給服務器
  • 服務器經過對比,發現app的唯一標識與wap網頁發上來的唯一標識能夠匹配
  • 服務器判斷,是同一個人操作,於是下發用戶個人數據

縱觀整個流程發現,一切的核心,一切的關鍵,就是那個唯一標示

選取唯一標識

這個唯一標識要具備苛刻的條件,想找到其實很不容易

  • 選擇當做唯一標識的內容,必須能讓app獲取的到
  • 選擇當做唯一標識的內容,必須也能讓wap獲取的到
  • 選擇當做唯一標識的內容,還必須有能力區分出不同的設備,如果選的唯一標識好幾個設備取出來的都一樣,那麼就亂套了

那麼我們看看遵循這幾個條件,我們能選擇啥?

  • UDID,MAC地址啥的,別說wap了,app都不可能取到了
  • JS有好幾套,通過網頁渲染canvas的方案獲取屏幕”指紋”,但這玩意app不可能拿到完全一致的東西,二者對不上,就沒任何意義
  • IDFA,IDFV,這玩意app是能取到了,但是wap拿不到啊

上面說的幾個都是相對來說,如果能雙方都拿到,是可以比較精準的進行設備唯一標識的,但問題是,我們拿不到。。怎麼辦?

看看下面幾個數據

  • 設備屏幕尺寸(iOS設備如此的統一,一共就那麼幾個屏幕尺寸,重複的還不一堆一堆的)
  • 設備操作系統(iOS系統碎片化如此的低,大部分幾乎都升到較高級的系統版本,重複的依然一堆一堆)
  • 設備IP(IP這玩意會變啊,離開WIFI進入3G,經常變,並且IP這玩意在同一WIFI下也重複的一堆一堆的啊)
  • 訪問時間(時間這玩意更沒譜了,你們的用戶量越大,某一個確定的時間段內,發生第一次安裝,重複的就越多)
  • 還有更多類似的數據

發現沒有,上面的數據最大的特點就是,有一定的描述設備體徵的信息,但是如果只靠這一個描述信息,那結果就是重複的太多太多,根本沒法確定一個唯一性。

但是,如果我們把這麼些描述信息做成一個合集,同一時間內滿足所有的條件,那麼這個設備重複的概率一下就縮減了太多太多。

舉例說明

舉個例子,到app安裝完畢第一次打開的時候,所有訪問過wap的設備信息,把他們的信息全都收集起來,找到同樣的屏幕尺寸,同樣的操作系統版本,同樣的IP地址,訪問時間相差不超過10min(暫定)的設備,在如此多得限定條件下,我們近乎可以認定爲,是具有唯一性的設備,是同一個人

可以看到這裏面衆多的信息一起去過濾,比較強的過濾條件就是IP,但因爲IP存在頻繁變化,所以追加了時間條件,IP也可能因爲WIFI路由器的原因導致,IP也存在重複和誤傷,這時候,又輔助了簡單的設備信息進行二次過濾。

這樣我們就找到了一個並不完美的唯一標識,有了這個唯一標識,就可以實現我們的跨瀏覽器和app的互通。

其實友盟的SDK就是這麼做的

友盟 SDK文檔

友盟通過這個方法,知道了用戶是從哪個網頁看到的app下載的廣告,然後發生的去appstore下載並運行的行爲,從而有效的能覈算廣告的收益

a.通過對應用appstore URL進行封裝,獲取分渠道點擊用戶的相關信息,包括:時間、IP、設備類型、操作系統版本;

b.通過在應用中集成代碼,獲取初次打開應用的用戶信息,包括:時間、IP、設備類型、操作系統版本;

c.實時對比不同渠道點擊用戶和應用激活用戶信息,區分不同渠道帶來的激活用戶;

d.此統計方式不用媒介提供統計數據,實時自動對比,會存在一定誤差,但可以基本衡量各渠道間及不同時期的渠道激活轉化數據。

方案弊端

他有什麼弊端嗎?弊端還是挺明顯的,因爲他是不完美的唯一標識,所以就存在着誤傷。

什麼是誤傷?用戶A瀏覽了WAP界面,用戶B恰巧用同一屏幕,同一操作系統版本,同一網段出口IP,在既定時間內,B用戶下載並運行了APP,這樣我們這套方案,會把B識別成A,等到A真的下載完APP後再來運行,數據可能已經失效了

這種誤傷是概率存在的,在現有的限定條件下,隨着app的用戶體量越來越大,這種誤傷將會越來越明顯。

iOSSafariCookie互通方案

方案簡介

接下來介紹另外一種方案,iOSSafariCookie互通,這種方案藉助的是iOS9系統新出的一個系統APISFSafariViewController,這個API是專爲Safari設計的。所以這套方案有他的特點

  • 優點:精準,不會誤傷。
  • 缺點:只能通過safari,不能借助QQ,微信,手百等第三方app的瀏覽器

感謝SafariAutoLoginTest這個demo項目提供的思路

SafariAutoLoginTest Github地址

方案思路

詳細說一下思路,如果我們能在用戶訪問wap頁面的時候,通過網頁,網手機裏寫入一些用戶的行爲和數據,比如用戶名,然後在app運行的時候去讀取這個信息,那麼就自然能建立起,wap頁面訪問,和app下載安裝後第一次運行,二者之間的聯繫。但是想要做到這一點,談何容易。

大家都知道,iOS是有沙盒的,不同app之間,幾乎不可能跨越沙盒屏障來訪問數據,wap在瀏覽器裏可以寫數據進入cookie,保存在手機上,這沒問題,但是app所在的cookie,和剛纔的外部瀏覽器所在的cookie,分屬不同沙盒,完全就不是同一份cookie。我們在wap上寫cookie寫進的是safari的cookie,我們打開自己app讀cookie讀得是自己app的cookie。

有什麼方法可以跨越沙盒傳遞數據?URL Scheme沒錯,通過OpenUrl的方式。如果我在wap頁面訪問,wap頁面發出來一個已經和我們的app約定好的URL Scheme跳轉,那麼就可以,喚起我們的app,並且伴隨着url,傳遞來數據。

如果用戶手機裏安裝了我們的app,用戶先去瀏覽wap頁面,wap頁面觸發了url跳轉,自動喚起了已經安裝的app,並且伴隨着url傳遞來了數據,一氣呵成,沒錯用戶很自然的從wap上的操作行爲,延續到了app上。

問題來了,如果用戶沒裝app怎麼辦?難道讓用戶先瀏覽Wap站,產生了行爲數據,被引導下載app,下載完後,重新回到wap站,重新再由wap站發起url跳轉?這體驗簡直渣到爆,簡直無法忍受

SFSafariViewController

iOS9以後,蘋果推出了SFSafariViewController這個全新的類,這個類的API允許在app內打開一個safari瀏覽器,而不是一個app內部的webview。

這個app內safari和外面系統的safari是同一個,共享同一個沙盒,可以操作同一個cookie

剛纔我們設想的操作流程,用戶體驗很差的流程

  • 用戶瀏覽wap站
  • 用戶引導下載app
  • 用戶回到wap站,跳轉app
  • wap通過openurl喚醒app傳遞數據

經過app內safari的處理,我們可以採用一些鬼點子,順着這個舊思路,把用戶體驗極差的第三部,第四部,給隱藏了,讓用戶無感知的靜默完成,這樣方案就完美了

  • 用戶通過safari瀏覽wap站,wap站寫用戶行爲數據進入cookie
  • 用戶通過引導下載app,運行app
  • 第一次運行app,app內靜默的打開一個純透明safari(讓用戶感覺不出來)
  • 純透明的safari訪問一個專門用來靜默取cookie得頁面
  • 純透明的safari訪問的取cookie的頁面,取到了正確的cookie數據,
  • 純透明的safari將數據通過openurl,靜默的回傳給app
  • app拿到瀏覽器數據後,銷燬無用的純透明safari

流程上看起來很複雜,但結果就是,用戶用系統safari,瀏覽了wap站,下載了app,app打開後就自動能恢復到他瀏覽wap站的個人信息了(或者其他數據)

VKSafariDomainBridge使用

這個工具已經不推薦使用了!!

原因是,SFViewController的方案在iOS10以後,Openurl事件會以各種方式被系統吞吃掉事件,duplicate事件,等等,因爲有了更好的替換方案,所以

所以非常非常不推薦繼續使用這個SafariAutoLogin方案了

上面的流程,如果用代碼進行開發還算挺麻煩的,所以我封裝了一個工具,來輔助進行這一串靜默讓用戶無感知的操作

VKSafariDomainBridge Github地址

按理說整個流程應該分爲2部分

  • wap頁面功能:
    • 用戶瀏覽wap頁的存cookie (wap地址1,用戶訪問用的)
    • 隱藏safari瀏覽的讀cookie頁面(wap地址2,靜默代碼訪問用的)
    • 隱藏safari跳轉openurl功能
  • app內功能:
    • 打開隱藏safari
    • 收聽openurl的回調,處理數據
    • 關閉隱藏safari

鑑於實在是不會h5相關的開發,所以我封裝的工具就只包含app內的功能


 

 

url的地址就是wap地址2,靜默代碼訪問用的
key作爲協議識別關鍵字,隱藏safari發起的跳轉,通過這個key識別,纔會走入VKSafariDomainBridge的處理邏輯,如果是其他正規渠道的openurl跳轉,key不匹配,便直接走正常邏輯,不會進行VKSafariDomainBridge處理

想要獲取wap用戶數據的時候


 

 

通過回調,如果成功success會返回YES,並且整個跳轉含有數據的url會被轉成string,通過block返回,如果失敗,則會返回NO

代碼分析

這個功能需要通過appdelegate的openurl回調來實現,既然是封裝工具,就要做到無侵入性,寫成category形式,只要使用者導入工程,便可以一行代碼不需要寫,自動生效。

application:openURL:options:這個方法,如果開發者沒有在工程中用到,我會自動添加,保證了openurl回調可以正常工作。

如果開發者已經在工程中使用,已經有很多使用者自己的openurl協議要處理了,那麼我的category會生成一個新方法,交換掉老的系統函數(MethodSwizzling),先判斷url協議裏是否含有上面提到的專屬Key,含有則走我的處理邏輯,如果不含有,調用老函數,保證原項目功能無異常。


 

 

接下來就是打開一個透明safari,等待來自網頁的openurl跳轉。製作透明safari的方法就是new出來後,alpha改爲0,直接present。


 

 

當透明safari加載完畢後,略微延遲後直接銷燬safari,如果在延遲期間,openurl返回則判斷,取cookie數據成功,回調成功,如果超時,就判斷取cookie數據失敗,回調失敗。

此處是SFSafariViewController的delegate回調


 

 

openUrl的邏輯就不細說明了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章