騰訊TBS是X5內核的升級版,能夠看成webview 來打開 網頁,能夠以用來打開docx doc pdf 等文件,這裏主要使用的是文件功能。
依賴接入 api 'com.tencent.tbs.tbssdk:sdk:43939'
這是筆者2021/2/25編輯時最新版本,最新可在官網查詢。
若是依賴文件下載有問題可手動下載jia包,本地依賴包可放在 app/libs 下,文件夾可自行建立,同時在 app/src/main/jniLibs/armeabi 下存放.so 文件。
再module 的gradle文件defaultConfig下添加android
ndk { abiFilters "armeabi", "x86", "mips", "armeabi-v7a" }
這是爲了不64位手機不兼容的狀況,強制打包。部分博客僅添加了 「armeabi」 一項。web
1 在繼承的application中初始化json
QbSdk.PreInitCallback cb = new QbSdk.PreInitCallback() { @Override public void onViewInitFinished(boolean arg0) { //x5內核初始化完成的回調,爲true表示x5內核加載成功,不然表示x5內核加載失敗,會自動切換到系統內核。 Log.e(TAG, "加載內核是否成功:" + arg0); } @Override public void onCoreInitFinished() { Log.e(TAG, "加載內核是否成功:"); } }; //x5內核初始化接口 QbSdk.initX5Environment(getApplicationContext(), cb);
這裏解釋下,initX5Environment初始化方法中回調是能夠寫作 null的,但爲了驗證是否成功加載內核,仍是有必要重寫一下方法。同時軟件須要獲取如下權限:api
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" />
注意動態權限讀寫內存和讀取手機狀態的獲取。
2 TBS的兩種使用
第一種是彈出式框使用安全
filepath = "/storage/emulated/0/aaa.docx"; HashMap<String, String> params = new HashMap<String, String>(); JSONObject jsonObject=new JSONObject(); try { jsonObject.put("pkgName", DocxActivity.this.getApplication().getPackageName()); } catch (JSONException e) { e.printStackTrace(); } params.put("style", "1"); params.put("local", "true"); //進入文件查看器 params.put("memuData", jsonObject.toString()); QbSdk.openFileReader(this,filepath, params,this);
結果如圖所示
文件路徑我使用的是根目錄,目前TBS不支持網絡預覽文件,所以須要下載後才能打開。hashmap的參數說明以下,style是界面風格,詳細可查看官方文檔,local是是否進入本地文件管理器,memuData是菜單選項。由json寫入。
第二種是使用本身activity 建立自定義view,這種形式更加靈活,可定製性更強。微信
public class MyTbsReadView extends FrameLayout implements TbsReaderView.ReaderCallback { private static final String TAG = "MyTbsReadView"; private TbsReaderView tbsReaderView; private int saveTime = -1; private Context context; private getFilepathListener getFilepathListener; public MyTbsReadView(@NonNull Context context) { this(context, null, 0); } public MyTbsReadView(@NonNull Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public MyTbsReadView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); tbsReaderView = new TbsReaderView(context, this); this.addView(tbsReaderView, new LinearLayout.LayoutParams(-1, -1)); this.context = context; } public void show(){ if (getFilepathListener != null) { getFilepathListener.getFilePath(this); } } private TbsReaderView getTbsView(Context context) { return new TbsReaderView(context, this); } public void display(File file){ if (file != null&& !TextUtils.isEmpty(file.toString())) { String tempfilefolder="/storage/emulated/0/TbsReaderTemp"; File tempfile=new File(tempfilefolder); if (!tempfile.exists()) { boolean flag= tempfile.mkdir(); if (flag) { Log.e(TAG, "display: success" ); } else { Log.e(TAG, "display: faile" ); } } Bundle bundle =new Bundle(); bundle.putString("filePath", file.toString()); bundle.putString("tempPath", Environment.getExternalStorageDirectory()+"/"+"TbsReaderTemp"); if (tbsReaderView == null) { this.tbsReaderView=getTbsView(context); } if (this.tbsReaderView.preOpen(getFileType(file.toString()),false)) { this.tbsReaderView.openFile(bundle); } }else { Log.e(TAG, "display: file path doesn't exists" ); } } private String getFileType(String toString) { String str=""; if (TextUtils.isEmpty(toString)) { return str; } int i=toString.lastIndexOf("."); if (i <= -1) { return str; } str=toString.substring(i+1); return str; } public void setGetFilepathListener(getFilepathListener listener) { this.getFilepathListener = listener; } @Override public void onCallBackAction(Integer integer, Object o, Object o1) { Log.e(TAG, "onCallBackAction: "+integer ); } public void onStop(){ if (tbsReaderView != null) { tbsReaderView.onStop(); } } public interface getFilepathListener { void getFilePath(MyTbsReadView myTbsReadView); } }
這裏是自定義view代碼 。繼承framelayout。使用回調填充TbsReaderView,關鍵代碼爲如下:網絡
Bundle bundle =new Bundle(); bundle.putString("filePath", file.toString()); bundle.putString("tempPath", Environment.getExternalStorageDirectory()+"/"+"TbsReaderTemp"); if (tbsReaderView == null) { this.tbsReaderView=getTbsView(context); } if (this.tbsReaderView.preOpen(getFileType(file.toString()),false)) { this.tbsReaderView.openFile(bundle); }
tbsReaderView 傳入bundle值,分別爲文件路徑和臨時文件路徑,須要注意的是TbsReaderTemp文件夾須要事先建立,但只要手機有騰訊系軟件如QQ,微信,此文件夾會事先存在。
在activity中使用代碼以下:app
filepath = "/storage/emulated/0/aaa.docx"; File myfile=new File(filepath); Log.e(TAG, "initView: "+myfile.length() ); myTbsReadView.setGetFilepathListener(new MyTbsReadView.getFilepathListener() { @Override public void getFilePath(MyTbsReadView myTbsReadView) { myTbsReadView.display(myfile); } }); myTbsReadView.show();
添加文件導入監聽,觸發時使用show函數,須要注意的是須要在activity銷燬時調用組件的onStop函數,不然再次打開會失敗。結果以下:
ide
筆者在使用時是建立demo的方式,仍是遇到了很多問題,這裏須要說明下:
1須要非安全http傳輸設置 即 manifest中networkSecurityConfig 和
usesCleartextTraffic的兩個屬性。 2在Android10以上非專有文件讀寫須要設置,經常使用的方法是減低限制 ,在nanifest文件中
requestLegacyExternalStorage`屬性設置爲true
3 manifest中provider函數
<!-- 非AndroidX使用 android:name="android.support.v4.content.FileProvider"--> <provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_file_paths"/> </provider>
provider_file_path文件以下
<?xml version="1.0" encoding="utf-8"?> <resources> <paths> <external-path path="" name="sdcard"/> </paths> </resources>
4 X5內核加載失敗,具體表現爲 「 not supported by:doc」 這個問題困擾筆者許久,最後的解決方式是在繼承的application文件中,即初始化X5中添加
QbSdk.setTbsListener(new TbsListener() { @Override public void onDownloadFinish(int i) { } @Override public void onInstallFinish(int i) { Log.e(TAG, "onInstallFinish: 內核下載安裝成功" ); } @Override public void onDownloadProgress(int i) { } }); boolean needDownload = TbsDownloader.needDownload(this, TbsDownloader.DOWNLOAD_OVERSEA_TBS); Log.e(TAG, "onCreate: "+needDownload ); if (needDownload) { TbsDownloader.startDownload(this); } TUIKit.init(this, GenerateTestUserSig.SDKAPPID, new ConfigHelper().getConfigs());
在加載內核失敗後從新下載,最後log提示安裝成功。