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