Android實(shí)現(xiàn)在線預(yù)覽office文檔的示例詳解
一、項(xiàng)目概述
在移動(dòng)端展示在線 Office 文檔(如 Word、Excel、PPT)是一項(xiàng)常見需求。用戶點(diǎn)擊鏈接即可在 App 內(nèi)預(yù)覽,無需下載應(yīng)用或文件到本地。實(shí)現(xiàn)該功能主要有兩種思路:
WebView + 在線文檔服務(wù):利用微軟 Office Online 或 Google Docs Viewer,將文檔 URL 嵌入預(yù)覽頁面;
第三方 SDK(如騰訊 TBS/WPS):集成瀏覽器內(nèi)核或文檔 SDK,支持在本地加載遠(yuǎn)程文檔并渲染顯示。
本文重點(diǎn)介紹兩種方案的實(shí)現(xiàn)方法,并給出完整例子。
二、相關(guān)技術(shù)知識(shí)
1.WebView 加載在線預(yù)覽
Office Online URL 模板:
https://view.officeapps.live.com/op/view.aspx?src=<URL_ENCODED_DOC_URL>
Google Docs Viewer:
https://docs.google.com/gview?embedded=true&url=<URL_ENCODED_DOC_URL>
WebView 配置:開啟 JavaScript、支持縮放、調(diào)整緩存策略等。
2.騰訊 TBS SDK(X5 內(nèi)核)
TBS 提供的 TbsReaderView 可加載 doc/docx/xls/ppt/pdf 等格式。
需在 App 初始化時(shí)預(yù)加載內(nèi)核,并在布局中添加 TbsReaderView。
3.文件訪問與權(quán)限
在線預(yù)覽不需讀寫權(quán)限;
若下載到本地后用 SDK 打開,則需申請(qǐng)存儲(chǔ)權(quán)限(Android 6.0+ 運(yùn)行時(shí)權(quán)限)。
4.性能與兼容
WebView 方案依賴外部網(wǎng)絡(luò)和服務(wù);
SDK 方案包體較大但支持離線,可自定義 UI。
三、實(shí)現(xiàn)思路
3.1 方案一:WebView + Office Online
在布局中放置一個(gè) WebView。
在 Activity 中取得文檔遠(yuǎn)程 URL,進(jìn)行 URL 編碼后拼接到 Office Online 查看地址。
配置 WebView:?jiǎn)⒂?JavaScript、DOM 存儲(chǔ)、縮放控制。
調(diào)用 webView.loadUrl(previewUrl) 即可在線預(yù)覽。
3.2 方案二:TBS SDK 離線預(yù)覽
在項(xiàng)目 build.gradle 中引入 TBS SDK 依賴。
在 Application 啟動(dòng)時(shí)初始化 X5:調(diào)用 QbSdk.initX5Environment(...)。
在布局中添加 TbsReaderView。
在 Activity 中下載或緩存文檔到本地,然后調(diào)用 tbsView.openFile(bundle, null) 加載預(yù)覽。
記得在 onDestroy() 中銷毀 TbsReaderView。
四、整合代碼
4.1 Java 代碼(MainActivity.java)
package com.example.officedocpreview; import android.Manifest; import android.content.pm.PackageManager; import android.net.Uri; import android.os.*; import android.view.View; import android.webkit.*; import android.widget.*; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import com.tencent.smtt.sdk.TbsReaderView; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; public class MainActivity extends AppCompatActivity { private static final int REQ_STORAGE = 1001; private WebView webView; private TbsReaderView tbsView; private FrameLayout container; private String remoteDocUrl = "https://example.com/test.docx"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); webView = findViewById(R.id.web_view); tbsView = findViewById(R.id.tbs_view); container = findViewById(R.id.tbs_container); findViewById(R.id.btn_web_preview).setOnClickListener(v -> previewWithWeb()); findViewById(R.id.btn_tbs_preview).setOnClickListener(v -> previewWithTbs()); } /** 方案一:WebView + Office Online */ private void previewWithWeb() { webView.setVisibility(View.VISIBLE); container.setVisibility(View.GONE); WebSettings ws = webView.getSettings(); ws.setJavaScriptEnabled(true); ws.setBuiltInZoomControls(true); ws.setDisplayZoomControls(false); ws.setDomStorageEnabled(true); String urlEncoded = Uri.encode(remoteDocUrl); String previewUrl = "https://view.officeapps.live.com/op/view.aspx?src=" + urlEncoded; webView.loadUrl(previewUrl); } /** 方案二:TBS SDK 預(yù)覽,需要存儲(chǔ)權(quán)限 */ private void previewWithTbs() { webView.setVisibility(View.GONE); container.setVisibility(View.VISIBLE); if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQ_STORAGE); } else { downloadAndOpenWithTbs(remoteDocUrl); } } @Override public void onRequestPermissionsResult(int req, @NonNull String[] perms, @NonNull int[] grantResults) { if (req == REQ_STORAGE && grantResults.length>0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { downloadAndOpenWithTbs(remoteDocUrl); } else { Toast.makeText(this, "存儲(chǔ)權(quán)限被拒絕", Toast.LENGTH_SHORT).show(); } } /** 下載到本地后用 TbsReaderView 打開 */ private void downloadAndOpenWithTbs(String urlStr) { new Thread(() -> { try { URL url = new URL(urlStr); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.connect(); InputStream is = conn.getInputStream(); File file = new File(getExternalFilesDir(null), "temp.docx"); FileOutputStream fos = new FileOutputStream(file); byte[] buf = new byte[4096]; int len; while ((len = is.read(buf))>0) fos.write(buf,0,len); fos.close(); is.close(); runOnUiThread(() -> openFileInTbs(file.getAbsolutePath())); } catch (Exception e) { e.printStackTrace(); runOnUiThread(() -> Toast.makeText(this, "下載失敗", Toast.LENGTH_SHORT).show()); } }).start(); } private void openFileInTbs(String filePath) { Bundle params = new Bundle(); params.putString(TbsReaderView.KEY_FILE_PATH, filePath); params.putString(TbsReaderView.KEY_TEMP_PATH, getExternalFilesDir(null).getPath()); boolean ok = tbsView.preOpen(getFileType(filePath), false); if (ok) { tbsView.openFile(params); } else { Toast.makeText(this, "TBS 內(nèi)核未加載或不支持", Toast.LENGTH_SHORT).show(); } } private String getFileType(String path) { if (path == null || !path.contains(".")) return ""; return path.substring(path.lastIndexOf('.') + 1); } @Override protected void onDestroy() { super.onDestroy(); tbsView.onStop(); } }
4.2 XML 布局與 Manifest
<!-- AndroidManifest.xml —— 聲明 INTERNET 與讀寫權(quán)限,并注冊(cè) TbsReaderView 權(quán)限 --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.officedocpreview"> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <application android:allowBackup="true" android:label="OfficePreview" android:icon="@mipmap/ic_launcher" android:theme="@style/Theme.AppCompat.Light.NoActionBar"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> </manifest> ???????<!-- activity_main.xml —— 同時(shí)包含 WebView 與 TbsReaderView --> <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- WebView 方式預(yù)覽 --> <WebView android:id="@+id/web_view" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="gone"/> <!-- TBS SDK 方式預(yù)覽 --> <FrameLayout android:id="@+id/tbs_container" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="gone"> <com.tencent.smtt.sdk.TbsReaderView android:id="@+id/tbs_view" android:layout_width="match_parent" android:layout_height="match_parent"/> </FrameLayout> <!-- 底部按鈕 --> <LinearLayout android:layout_gravity="bottom|center_horizontal" android:orientation="horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="16dp"> <Button android:id="@+id/btn_web_preview" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Web 預(yù)覽"/> <Button android:id="@+id/btn_tbs_preview" android:layout_marginStart="16dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="TBS 預(yù)覽"/> </LinearLayout> </FrameLayout>
五、代碼解讀
1.WebView 方案
將文檔 URL 進(jìn)行 URL 編碼后拼接到 Office Online 查看地址;
在 WebView 中啟用 JavaScript、縮放支持及 DOM 存儲(chǔ);
直接 loadUrl() 即可,無需額外下載。
2.TBS SDK 方案
需提前在 Application 或任意時(shí)機(jī)調(diào)用 QbSdk.initX5Environment()(省略);
下載文檔到 App 私有存儲(chǔ)后,通過 TbsReaderView.preOpen() 檢測(cè)內(nèi)核支持;
調(diào)用 openFile() 加載本地文檔,支持 doc、xls、ppt、pdf 等多種格式;
在 onDestroy() 中調(diào)用 tbsView.onStop() 釋放資源。
3.權(quán)限與生命周期
運(yùn)行時(shí)申請(qǐng)寫存儲(chǔ)權(quán)限后才能保存到本地;
在 onPause()/onDestroy() 清理動(dòng)畫和 TBS 資源,避免內(nèi)存泄漏。
六、項(xiàng)目總結(jié)
WebView + Office Online:實(shí)現(xiàn)簡(jiǎn)單、無需集成第三方 SDK,依賴外部服務(wù);
TBS SDK:支持離線預(yù)覽和更多格式,但包體較大、需初始化內(nèi)核;
本文示例將兩種方案合二為一,按需選擇并切換。
七、實(shí)踐建議與未來展望
UI 優(yōu)化:增加加載進(jìn)度條、錯(cuò)誤頁面提示;
緩存策略:對(duì)已下載文件做緩存,下次直接讀??;
更多格式:結(jié)合 open-source 渲染庫(如 Apache POI + PDF 轉(zhuǎn)換)實(shí)現(xiàn)更多定制;
Compose 時(shí)代:在 Jetpack Compose 中也可直接使用 AndroidView 嵌入 WebView 或 TBS。
到此這篇關(guān)于Android實(shí)現(xiàn)在線預(yù)覽office文檔的示例詳解的文章就介紹到這了,更多相關(guān)Android在線預(yù)覽office內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解析Java的迭代器中的fast-fail錯(cuò)誤檢測(cè)機(jī)制
這篇文章主要介紹了Java的迭代器中的fast-fail錯(cuò)誤檢測(cè)機(jī)制,需要的朋友可以參考下2016-02-02Android 實(shí)現(xiàn)當(dāng)下最流行的吸頂效果
本文主要介紹了Android 實(shí)現(xiàn)當(dāng)下最流行的吸頂效果的示例代碼。具有很好的參考價(jià)值,下面跟著小編一起來看下吧2017-03-03詳解Android中Runtime解決屏幕旋轉(zhuǎn)問題(推薦)
這篇文章主要介紹了Runtime解決屏幕旋轉(zhuǎn)問題的方法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-09-09Android開發(fā)實(shí)現(xiàn)的導(dǎo)出數(shù)據(jù)庫到Excel表格功能【附源碼下載】
這篇文章主要介紹了Android開發(fā)實(shí)現(xiàn)的導(dǎo)出數(shù)據(jù)庫到Excel表格功能,涉及Android數(shù)據(jù)庫及Excel表格相關(guān)操作技巧,并附帶完整源碼供讀者下載參考,需要的朋友可以參考下2018-03-03android nfc常用標(biāo)簽讀取總結(jié)
NFC(Near Field Communication,近場(chǎng)通信)是一種數(shù)據(jù)傳輸技術(shù)這篇文章主要介紹了android nfc常用標(biāo)簽讀取總結(jié),有興趣的可以了解一下。2016-12-12Jetpack?Compose實(shí)現(xiàn)點(diǎn)擊事件click的多種方法
這篇文章主要介紹了Jetpack?Compose實(shí)現(xiàn)點(diǎn)擊事件的多種方法,Jetpack?Compose是一款基于Kotlin的聲明式UI工具包,可以方便地創(chuàng)建漂亮的用戶界面,下面我們就來看看Jetpack?Compose添加點(diǎn)擊事件都可以怎么實(shí)現(xiàn)2024-02-02Android使用自定義View實(shí)現(xiàn)橫行時(shí)間軸效果
這篇文章主要給大家介紹了關(guān)于Android使用自定義View實(shí)現(xiàn)橫行時(shí)間軸效果的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Android具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12Android Dialog 設(shè)置字體大小的具體方法
這篇文章介紹了Android Dialog 設(shè)置字體大小的具體方法,希望能幫助到有同樣需求的朋友,可能我的方法不是最好的,也希望有朋友指點(diǎn)2013-09-09Android端實(shí)現(xiàn)單點(diǎn)登錄的方法詳解
所謂單點(diǎn)登錄就是指的同一個(gè)賬戶(id)不能在一個(gè)以上的設(shè)備上登錄對(duì)應(yīng)的用戶系統(tǒng)(排除web端和移動(dòng)端可以同時(shí)登錄的情況),例如:用戶m在A設(shè)備登錄并保持登錄狀態(tài),然后又在B設(shè)備登錄,此時(shí)A應(yīng)該要強(qiáng)制下線,m無法在A設(shè)備上繼續(xù)執(zhí)行用戶相關(guān)的操作,下面來一起看看吧。2016-11-11Android實(shí)現(xiàn)移動(dòng)小球和CircularReveal頁面切換動(dòng)畫實(shí)例代碼
這篇文章主要給大家介紹了關(guān)于利用Android如何實(shí)現(xiàn)移動(dòng)的小球和CircularReveal頁面切換動(dòng)畫的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)各位Android開發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。2017-09-09