Android 原生 Intent 分享支持的那些事
一、前言
對(duì)于一個(gè) App 而言,分享是一個(gè)比較常見的功能。分享的主要功能,還是為了讓 App 在用戶之間形成一個(gè)自傳播的效果,但是對(duì)于開發(fā)者而言,分享就是在不同的 App 之間,傳遞文本、文件等數(shù)據(jù)。
如果只是簡單的分享內(nèi)容,使用 ACTION_SEND 或者 ACTION_SEND_MULTIPLE 可能是一種簡單的方式??墒菑?Support v4 22.0.0 開始,引入了一個(gè)新的分享兼容庫,ShareCompat ,它可以幫開發(fā)者更輕松的構(gòu)造一個(gè)分享的 Intent 。
二、ShareCompat
2.1 什么是 ShareCompat
ShareCompat 可以幫助我們快速的實(shí)現(xiàn)應(yīng)用間分享的數(shù)據(jù)的功能。既然是一個(gè)完整的功能,它主要包含了兩個(gè)功能:快速的構(gòu)建一個(gè)分享的 Intent,快速的讀取別的 App 內(nèi)分享來的內(nèi)容。
所以,ShareCompat 是包含兩部分內(nèi)容的:IntentBuilder 、IntentReader。從名稱上就可以看出來他們的用途。
2.2 分享文本
從最簡單的開始,使用 IntentBuilder 分享一個(gè)純文本,是非常簡單的,IntentBuilder 從名稱也能看出來,它是 Builder 模式,所以可以支持多個(gè)方法鏈?zhǔn)秸{(diào)用。
其中最重要的是,設(shè)置一個(gè)正確的 mimeType,它將是用于 Intent-filter 過濾器重要的過濾條件,表示這里知識(shí)分享一個(gè)純文本的類型的內(nèi)容。
在 startActivity() 之前,調(diào)用 resolveActivity() 做一層校驗(yàn),是一個(gè)比較常規(guī)的保護(hù)措施。它避免了當(dāng)前系統(tǒng)中沒有任何 App 可以匹配上這個(gè)隱式的 Intent,而觸發(fā)ActivityNotFoundException 的異常。雖然沒有可以接收 text/plain 類型的分享其實(shí)是非常不可能的,但是加上它也是一個(gè)很好的編碼習(xí)慣。
2.3 分享 HTML 格式的文本
有一些 App ,例如 電子郵件客戶端,是可以支持 HTML 格式的文本的,與純文本相比,它可以顯示更豐富的內(nèi)容。
可以注意到,區(qū)別就在于 setType() 的時(shí)候,填寫的是 text/html ,并且使用的是 setHtmlText() 方法去配置分享的內(nèi)容。
既然分享 Html 內(nèi)容,多用于發(fā)送 Email 內(nèi)容,所以這里也配置了接收的郵件地址。
一般而言,使用 Html 的方式還需要接收分享內(nèi)容的 App 支持這樣的內(nèi)容,所以還是需要謹(jǐn)慎使用,可能用戶分享的 App ,并不能很好的顯示我們需要分享的 Html 的內(nèi)容。
2.4 發(fā)送一個(gè)Email
前面也提到如何在發(fā)送的 Email 中,添加一個(gè) Html 的內(nèi)容。而 ShareCompat 也提供了非常好的發(fā)送 Email 的體驗(yàn),可以非常方便的構(gòu)造一個(gè)用于發(fā)送 Email 的 Intent。
IntentBuilder 中,提供了非常方便的 Api,用于添加一些 Email 收件人、抄送之類的數(shù)據(jù),都在 addEmailXxx() 的方法中,非常好理解,有興趣的可以直接看看 Api 文檔。
2.5 收一個(gè)文本內(nèi)容
雖然大多數(shù)情況下,我們是需要開發(fā)一個(gè)支持分享的功能,但是也不影響我們了解如何接收一個(gè)分享的內(nèi)容。
而分享傳遞過來的內(nèi)容,都是可以在 Intent 中獲取到的。而 IntentReader 也提供了非常便捷的 Api 讓我們快速的拿到它的內(nèi)容。
這里以接收一個(gè)文本內(nèi)容為例,首先需要在 AndroidManifest.xml 中配置接收的 Activity 和 Intent-filter。
這就是一個(gè)比較常規(guī)的 ShareActivity 的配置。
IntentReader 使用起來也非常的簡單,它實(shí)際上就是一個(gè) Intent 數(shù)據(jù)的包裝器,提供了很多方便的 Api ,從 Intent 中提取出我們需要的數(shù)據(jù)。
2.6 分享文件和圖片
除了分享一段文本內(nèi)容之外,有時(shí)候我們還需要向外分享一個(gè)文件(包括視頻、圖片等)。而發(fā)送這些,就需要具有額外的權(quán)限。
構(gòu)造一個(gè)圖片的分享也非常的簡單,只需要使用 setStream() 方法,傳遞一個(gè)文件的 Uri 即可,并且配置好對(duì)應(yīng)的 mimeType。
但是這種方式,就需要考慮到 Android 6.0 開始對(duì)分享的文件,以嚴(yán)格模式進(jìn)行處理,所以對(duì)此我們需要使用 FileProvider 來支持。
有關(guān) FileProvider 的內(nèi)容,可以看看之前的文章:《我想把 FileProvider 聊的更透徹一些》
一旦使用上 FileProvider 只需要將 Uri 替換成 FileProvider.getUriForFile() 返回的 Uri 即可,這都是 FileProvider 的標(biāo)準(zhǔn)內(nèi)容,就不在這里詳細(xì)說明了。
不過有一點(diǎn)需要特別注意的,使用 FileProvider 返回的 Uri ,就可以不用顯式的設(shè)定 mimeType 類型了,因?yàn)樗强梢酝ㄟ^這個(gè) Uri 推斷出正確的 mimeType 的類型的,所以就不需要顯式的指定了。
2.7 接收文件內(nèi)容
Android 6.0 對(duì)文件的接收,并沒有任何的改變,所以我們只需要使用 IntentReader.getStream() 這個(gè)標(biāo)準(zhǔn)的 Api 就可以拿到分享過來的 Uri。
三、ShareCompat 都兼容了什么
Support v4 包下的庫,其實(shí)都是為了向 Android 低版本做兼容而努力的,讓開發(fā)者無需關(guān)注他們之間的差異,而通常我們看到一個(gè)類的命名中,有 Compat 字樣,一般就可以斷定,它又是一個(gè)兼容庫。
那么 ShareCompat 對(duì)不同的 Android 版本,有做什么兼容處理呢?
ShareCompat 中,有一個(gè)靜態(tài)的 ShareCompatImpl 對(duì)象,它就是為了出來兼容問題的,它是一個(gè)接口,先來看看它的定義。
可以看到,它實(shí)際上就是對(duì) configureMenuItem() 和 html 的文本轉(zhuǎn)義,做了兼容的處理。
在 ShareCompat 的靜態(tài)代碼塊中,對(duì)其進(jìn)行版本的區(qū)分,不同版本用不同的實(shí)現(xiàn)類。
簡單來說,就是一些處理方法,可能在低版本上沒有,所以它會(huì)使用另外的方法去實(shí)現(xiàn)。舉個(gè)例子,ShareCompatImplJB 中,escapeHtml() 方法,最終調(diào)用的是 Html.escapeHtml() 方法,但是這個(gè)方法它是 Api Level 16 才有的支持,所以在 ShareCompatImplBase 中,實(shí)際上是把它的實(shí)現(xiàn),完全的拷貝了出來,只是為了做一個(gè) Html 中字符的轉(zhuǎn)義。
四、結(jié)語
ShareCompat 如果只是簡單的去分享一個(gè)內(nèi)容,還是非常的好用的。但是大多數(shù)情況下,我們還是會(huì)選擇使用第三方 App 提供的 SDK,來進(jìn)行接入支持,因?yàn)闀?huì)有一些定制的需要,例如拿到分享結(jié)果。
不過這并不影響我們了解 ShareCompat ,多看看 Google 開發(fā)人員寫的代碼,終歸是對(duì)你有幫助的。
【本文為51CTO專欄作者“張旸”的原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)通過微信公眾號(hào)聯(lián)系作者獲取授權(quán)】