基於騰訊瀏覽服務 TBS 實現應用內打開並瀏覽 Office 文件

衆所周知,Android App 在國內環境下實現應用內打開本地或位於遠程服務器上 word、excel、pdf 等 Office 文檔的功能遠遠沒有 iOS 系統方便得多。以前也寫過一篇文章,羅列出現有解決方案間的優劣對比。直到最近,在網上又發現一種新的解決方案:騰訊瀏覽服務(簡稱:TBS)。html

TBS 簡單介紹


正如官網所言,依託 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 網站,有須要的朋友能夠訪問地址:

github.com/Mike-bel/Tb…

關於我:亦楓,博客地址:yifeng.studio/,新浪微博:IT亦楓

微信掃描二維碼,歡迎關注個人我的公衆號:安卓筆記俠

不只分享個人原創技術文章,還有程序員的職場遐想

相關文章
相關標籤/搜索