衆所周知,Android App 在國內環境下實現應用內打開本地或位於遠程服務器上 word、excel、pdf 等 Office 文檔的功能遠遠沒有 iOS 系統方便得多。以前也寫過一篇文章,羅列出現有解決方案間的優劣對比。直到最近,在網上又發現一種新的解決方案:騰訊瀏覽服務(簡稱:TBS)。html
正如官網所言,依託 X5 內核強大的能力,TBS 致力於提供優化移動端瀏覽體驗的整套解決方案。TBS 雖然核心在於提供一套 SDK 解決傳統 WebView 的諸多使用問題。可是,利用其加強瀏覽能力,咱們還可以使用這套 SDK 實現應用內的文件瀏覽功能、視頻播放功能等。更多詳細功能,能夠參考官網介紹:java
x5.tencent.com/tbs/product…android
然而,美中不足的是,在瀏覽文件方面,官方沒有提供完善的使用文檔和 Demo 案例。通過一番折騰,和借鑑這篇文章 ,總算可以實現應用內打開 Office 文檔的功能,因而整理於此。git
注意:TBS 只能打開瀏覽本地文件,對於位於服務器的遠程文件,沒法實如今線預覽,只能經過先下載再打開的方式進行瀏覽。這裏咱們先來看看如何使用 TBS 打開本地文件。程序員
首先仍是添加 SDK 依賴。下載 TBS 提供的 jar 包和 so 文件,添加到工程中對應的 libs 和 jniLibs 目錄下。如圖:github
而後在 app/build.gradle 文件中對 libs 目錄中 jar 文件的依賴能夠是這樣:服務器
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}複製代碼
須要注意的是:TBS 目前只提供 armeabi 類型 CPU 架構的 so 庫。固然,也能夠將 so 文件放置於 libs 目錄下,只不過須要在 app/build.gradle 中額外修改 so 文件依賴配置:微信
android {
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
}複製代碼
配置完成以後,再來看看如何使用。這裏主要使用的是 TbsReaderView
類。在宿主 Activity 中實現 ReaderCallback
接口,並經過 Java 代碼動態建立 TbsReaderView 對象,將其添加到 content view 當中。好比:架構
mTbsReaderView = new TbsReaderView(this, this);
RelativeLayout rootRl = (RelativeLayout) findViewById(R.id.rl_root);
rootRl.addView(mTbsReaderView, new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT))複製代碼
ReaderCallback
接口提供的方法能夠不予處理(目前不知道有什麼用途,可是必定要實現這個接口類):app
@Override
public void onCallBackAction(Integer integer, Object o, Object o1) {
}複製代碼
可能你會有疑惑,爲何不將 TbsReaderView
放在 layout 佈局文件中,而是在代碼中手動 add 進去。經測試,這麼作會報錯,提示找不到這個類。而後咱們查看 TbsReaderView
源碼,發現只有這麼一個構造函數:
public TbsReaderView(Context var1, TbsReaderView.ReaderCallback var2) {
super(var1.getApplicationContext());
if(!(var1 instanceof Activity)) {
throw new RuntimeException("error: unexpect context(none Activity)");
} else {
this.d = var2;
this.a = var1;
this.e = new au(this);
}
}複製代碼
而沒有提供含 AttributeSet
類型參數的構造函數,也就是說,這個版本的 TBS 只容許咱們經過 new 的方式建立 TbsReaderView
實例並使用。
說完這個,再接着看如何打開本地文件。代碼也很簡單:
private void displayFile() {
Bundle bundle = new Bundle();
bundle.putString("filePath", getLocalFile().getPath());
bundle.putString("tempPath", Environment.getExternalStorageDirectory().getPath());
boolean result = mTbsReaderView.preOpen(parseFormat(mFileName), false);
if (result) {
mTbsReaderView.openFile(bundle);
}
}複製代碼
能夠看到,經過 Bundle
類型參數的形式向 TbsReaderView
對象傳遞文件地址和另外一個臨時目錄地址。這兩個數據,缺一不可。
這裏可能你們又有疑問,沒有文檔介紹,咱們是如何知道 Bundle
參數傳遞哪些數據的呢?仍是查看 TbsReaderView
源碼,在該類中存在這兩個成員變量:
public static final String KEY_FILE_PATH = "filePath";
public static final String KEY_TEMP_PATH = "tempPath";複製代碼
第一個參數很好理解,第二個參數不知道什麼意思,根據名字須要的應該是一個臨時目錄地址,反正傳上就對了。這裏順便教你們兩個技巧,之後閱讀 Jar 包源碼時也許可以用得上:
1,如何搜索 jar 包中的指定類文件?
使用 jar -tf
命令可以列出 jar 包中的內容,若是再配上 grep 命令便能搜索指定類文件,如:
yifeng:desktop yifeng $ jar -tf tbs_sdk_thirdapp.jar | grep -i TbsReaderView
com/tencent/smtt/sdk/TbsReaderView$ReaderCallback.class
com/tencent/smtt/sdk/TbsReaderView.class複製代碼
2,如何搜索 jar 包中的指定字符串?
使用 zipgrep 命令,若是搜索的關鍵字包含空格,則須要使用引號:
yifeng:desktop yifeng $ zipgrep filePath tbs_sdk_thirdapp.jar
com/tencent/smtt/sdk/TbsReaderView.class:Binary file (standard input) matches複製代碼
回到 TBS 使用上,最後別忘了在 onDestroy()
生命週期函數中添加:
@Override
protected void onDestroy() {
super.onDestroy();
mTbsReaderView.onStop();
}複製代碼
至此,使用 TBS 實現應用內打開預覽本地 Office 文件的所有過程結束,咱們來看一下效果圖:
能夠看到,第一次使用須要下載騰訊提供的 pdf 瀏覽插件,以後打開時則無需再次加載。
更多時候,咱們預覽的文件都位於遠程服務器上。因此,咱們須要預先下載文件,下載完成以後再使用 TBS 打開本地文件。感興趣的話,不妨繼續來看。
Android App 下載文件的方式有不少,這裏咱們使用一種最簡單的方式來作,利用系統提供的 DownloadManager
類來實現下載功能,並監聽下載進度。
先來看看如何利用 DownloadManager
下載文件。根據使用場景,這裏我屏蔽默認的通知欄提示消息,並設置本地存放位置,相關代碼以下:
mDownloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(mFileUrl));
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, mFileName);
request.allowScanningByMediaScanner();
request.setNotificationVisibility(Request.VISIBILITY_HIDDEN);
mRequestId = mDownloadManager.enqueue(request);複製代碼
而後是監聽下載進度,使用的是 ContentObserver
類。自定義一個繼承自 ContentObserver
的監聽類:
private class DownloadObserver extends ContentObserver {
private DownloadObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
queryDownloadStatus();
}
}複製代碼
在 onChange()
回調方法中實時查詢下載進度。當查詢到下載完成時,使用 TBS 打開下載到本地對應目錄的文件:
private void queryDownloadStatus() {
DownloadManager.Query query = new DownloadManager.Query().setFilterById(mRequestId);
Cursor cursor = null;
try {
cursor = mDownloadManager.query(query);
if (cursor != null && cursor.moveToFirst()) {
//已經下載的字節數
int currentBytes = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
//總需下載的字節數
int totalBytes = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
//狀態所在的列索引
int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
Log.i("downloadUpdate: ", currentBytes + " " + totalBytes + " " + status);
mDownloadBtn.setText("正在下載:" + currentBytes + "/" + totalBytes);
if (DownloadManager.STATUS_SUCCESSFUL == status && mDownloadBtn.getVisibility() == View.VISIBLE) {
mDownloadBtn.setVisibility(View.GONE);
mDownloadBtn.performClick();
}
}
} finally {
if (cursor != null) {
cursor.close();
}
}
}複製代碼
作好這些準備後,在下載文件的時候註冊監聽:
mDownloadObserver = new DownloadObserver(new Handler());
getContentResolver().registerContentObserver(Uri.parse("content://downloads/my_downloads"), true, mDownloadObserver);複製代碼
並在 onDestroy()
方法中取消監聽:
@Override
protected void onDestroy() {
super.onDestroy();
if (mDownloadObserver != null) {
getContentResolver().unregisterContentObserver(mDownloadObserver);
}
}複製代碼
最後,別忘記在 Manifest 清單文件中添加相應使用權限(權限含義,就再也不一一介紹):
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION"/>
<uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER"/>
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>複製代碼
整體來看,TBS 提供的文件瀏覽功能仍是很強大的。據官網介紹,目前可以支持 42 種不一樣格式的文件。除此以外,TBS 還有一些其餘的用途也很是值得嘗試。只是,期待官方可以提供更多的使用文檔介紹,幫助咱們更方便地使用起來。
備註:
本文相關代碼已上傳至 GitHub 網站,有須要的朋友能夠訪問地址:
關於我:亦楓,博客地址:yifeng.studio/,新浪微博:IT亦楓
微信掃描二維碼,歡迎關注個人我的公衆號:安卓筆記俠
不只分享個人原創技術文章,還有程序員的職場遐想
![]()