有时我们在APP里会有浏览的需求,常见的文件有Word、Excel、ppt、pdf等格式的文件,这里我选用了腾讯的TBS浏览服务。在这里记录一下,方便以后使用,有需要的朋友也可以参考一下。下面就来看一下怎样集成TBS。
先来张效果图看下
首先下载腾讯浏览服务SDK,下载地址:https://x5.tencent.com/tbs/sdk.html,接入文档地址:https://x5.tencent.com/tbs/guide/sdkInit.html,下载完导入jar包和.so文件。
在app的build.gradle里配置
android {
compileSdkVersion 28
defaultConfig {
……
//X5兼容64位手机
ndk {
abiFilters "armeabi", "armeabi-v7a", "x86", "mips"
}
}
buildTypes {
……
}
}
dependencies {
……
//网络请求okhttp3
implementation 'com.squareup.okhttp3:okhttp:3.12.0'
//Retrofit2库
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
//gson解析
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
//TBS腾讯浏览服务
implementation files('libs/tbs_sdk_thirdapp_v4.3.0.1148_43697_sharewithdownloadwithfile_withoutGame_obfs_20190805_175505.jar')
}
在AndroidManifest.xml里加入如下权限
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
在Application 的onCreat()里加入
//增加这句话
QbSdk.initX5Environment(this,null);
自定义一个现实文件的ViewSuperFileView
package com.wjy.project.mytbs;
import android.content.Context;
import android.os.Bundle;
import android.os.Environment;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import com.tencent.smtt.sdk.TbsReaderView;
import java.io.File;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
/**
* Created by wjy on 2020/2/11
* 自定义文件打开阅读View
*/
public class SuperFileView extends FrameLayout implements TbsReaderView.ReaderCallback {
private static String TAG = "SuperFileView";
private Context context;
private TbsReaderView mTbsReaderView;
private OnGetFilePathListener mOnGetFilePathListener;
public OnGetFilePathListener getOnGetFilePathListener() {
return mOnGetFilePathListener;
}
public void setOnGetFilePathListener(OnGetFilePathListener mOnGetFilePathListener) {
this.mOnGetFilePathListener = mOnGetFilePathListener;
}
public SuperFileView(@NonNull Context context) {
this(context, null, 0);
}
public SuperFileView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public SuperFileView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
mTbsReaderView = new TbsReaderView(context, this);
this.addView(mTbsReaderView, new LinearLayout.LayoutParams(-1, -1));
}
@Override
public void onCallBackAction(Integer integer, Object o, Object o1) {
Log.e(TAG,"****************************************************" + integer);
}
/***
* 获取File路径
*/
public interface OnGetFilePathListener {
void onGetFilePath(SuperFileView mSuperFileView);
}
/**
* 展示
*/
public void show() {
if(mOnGetFilePathListener!=null){
mOnGetFilePathListener.onGetFilePath(this);
}
}
/**
* 显示文件的界面,退出界面以后需要销毁,否则再次加载文件无法加载成功,会一直显示加载文件进度条。
*/
public void onStopDisplay() {
if (mTbsReaderView != null) {
mTbsReaderView.onStop();
}
}
/**
* 显示文件
*/
public void displayFile(File mFile){
if (mFile != null && !TextUtils.isEmpty(mFile.toString())){
//增加下面一句解决没有TbsReaderTemp文件夹存在导致加载文件失败
String bsReaderTemp = "/storage/emulated/0/TbsReaderTemp";//SD卡下面文件路径
File bsReaderTempFile =new File(bsReaderTemp);
if (!bsReaderTempFile.exists()){//如果SD卡下不存在TbsReaderTemp文件夹
Log.e(TAG,"准备在SD卡下创建TbsReaderTemp文件夹!");
boolean mkdir = bsReaderTempFile.mkdir();
if(!mkdir){
Log.e(TAG,"创建/storage/emulated/0/TbsReaderTemp失败!!!!!");
}
}
//加载文件
Bundle localBundle = new Bundle();
Log.e(TAG,"mFile.toString()="+mFile.toString());
localBundle.putString("filePath", mFile.toString());
localBundle.putString("tempPath", Environment.getExternalStorageDirectory() + "/" + "TbsReaderTemp");
if (mTbsReaderView == null){
mTbsReaderView = new TbsReaderView(context,this);
}
boolean bool = mTbsReaderView.preOpen(getFileType(mFile.toString()), false);
if (bool){
mTbsReaderView.openFile(localBundle);
}
}else {
Log.e(TAG,"文件路径无效!");
}
}
/***
* 获取文件类型
*
* @param paramString
* @return
*/
private String getFileType(String paramString){
String str = "";
if (TextUtils.isEmpty(paramString)) {
Log.e(TAG, "paramString---->null");
return str;
}
Log.e(TAG, "paramString:" + paramString);
int i = paramString.lastIndexOf('.');
if (i <= -1) {
Log.e(TAG, "i <= -1");
return str;
}
str = paramString.substring(i + 1);
Log.e(TAG, "paramString.substring(i + 1)------>" + str);
return str;
}
}
之后就可以在使用了,新建打开文件的Activity页面FileDisplayActivity
package com.wjy.project.mytbs;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import androidx.annotation.Nullable;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Created by wjy on 2020/2/11
* 文件打开阅读页面
*/
public class FileDisplayActivity extends Activity {
SuperFileView mSuperFileView;
String filePathUrl;
private TextView tv_progress;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_filedisplay);
filePathUrl = getIntent().getStringExtra("filePath");
Log.e("tag","filePathUrl="+filePathUrl);
init();
}
private void init(){
tv_progress = findViewById(R.id.tv_progress);
mSuperFileView = findViewById(R.id.mSuperFileView);
mSuperFileView.setOnGetFilePathListener(new SuperFileView.OnGetFilePathListener() {
@Override
public void onGetFilePath(SuperFileView mSuperFileView) {
openFile(filePathUrl,mSuperFileView);//获取文件路径并打开文件
}
});
mSuperFileView.show();
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.e("tag","FileDisplayActivity-->onDestroy");
if (mSuperFileView != null) {
mSuperFileView.onStopDisplay();
}
}
/**
* 打开文件文件
* @param filePathUrl
* @param mSuperFileView
*/
private void openFile(final String filePathUrl,final SuperFileView mSuperFileView){
//从缓存获取文件
File cacheFile = FileTools.getCacheFile(filePathUrl);
if (cacheFile.exists()) {//如果文件存在
if (cacheFile.length() <= 0) {
Log.e("tag", "删除空文件!!");
cacheFile.delete();
return;
}
Log.e("tag","如果文件存在"+cacheFile.exists());
mSuperFileView.displayFile(cacheFile);//直接打开文件
}else {
tv_progress.setVisibility(View.VISIBLE);
//如果文件不存在,则在网络先下载然后再打开
requestDownLoadFile();
}
}
/**
* 从网络下载文件
*/
private void requestDownLoadFile(){
//网络下载
LoadFileModel.loadFile(filePathUrl, new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
Log.e("tag", "下载文件-->onResponse");
InputStream is = null;
byte[] buf = new byte[2048];
int len = 0;
FileOutputStream fos = null;
try {
ResponseBody responseBody = response.body();
is = responseBody.byteStream();
long total = responseBody.contentLength();
File file1 = FileTools.getCacheDir();
if (!file1.exists()) {
file1.mkdirs();
Log.e("tag", "创建缓存目录: " + file1.toString());
}
File fileN = FileTools.getCacheFile(filePathUrl);
Log.e("tag", "创建缓存文件: " + fileN.toString());
if (!fileN.exists()) {
boolean mkdir = fileN.createNewFile();
}
fos = new FileOutputStream(fileN);
long sum = 0;
while ((len = is.read(buf)) != -1) {
fos.write(buf, 0, len);
sum += len;
int progress = (int) (sum * 1.0f / total * 100);
Log.e("tag", "写入缓存文件" + fileN.getName() + "进度: " + progress);
}
fos.flush();
Log.e("tag", "文件下载成功,准备展示文件。");
tv_progress.setVisibility(View.GONE);
mSuperFileView.displayFile(fileN);
} catch (Exception e) {
Log.e("tag", "文件下载异常 = " + e.toString());
} finally {
try {
if (is != null)
is.close();
} catch (IOException e) {
}
try {
if (fos != null)
fos.close();
} catch (IOException e) {
}
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.e("tag", "文件下载失败");
File file = FileTools.getCacheFile(filePathUrl);
if (!file.exists()) {
Log.e("tag", "删除下载失败文件");
file.delete();
requestDownLoadFile();//重新下载
}
}
});
}
}
布局文件activity_filedisplay.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.wjy.project.mytbs.SuperFileView
android:id="@+id/mSuperFileView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<TextView
android:id="@+id/tv_progress"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#E7E7E7"
android:text="文件加载中"
android:textColor="#999999"
android:textSize="18sp"
android:gravity="center"
android:visibility="gone"/>
</RelativeLayout>
里面用到的一个工具类FileTools
package com.wjy.project.mytbs;
import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;
import java.io.File;
/**
* Created by wjy on 2020/2/11
* 文件工具类
*/
public class FileTools {
public static String pathName = Environment.getExternalStorageDirectory().getAbsolutePath() + "/TbsReaderTemp/";
/***
* 获取缓存目录
* @return
*/
public static File getCacheDir() {
return new File(pathName);
}
/***
* 绝对路径获取缓存文件
* @param url
* @return
*/
public static File getCacheFile(String url) {
File cacheFile = new File(pathName + getFileName(url));
Log.e("tag", "缓存文件 = " + cacheFile.toString());
return cacheFile;
}
/***
* 根据链接获取文件名(带类型的),具有唯一性
* @param url
* @return
*/
private static String getFileName(String url) {
String fileName = Md5Tool.hashKey(url) + "." + getFileType(url);
Log.e("tag","fileName="+fileName);
return fileName;
}
/***
* 获取文件类型
* @param paramString
* @return
*/
private static String getFileType(String paramString) {
String str = "";
if (TextUtils.isEmpty(paramString)) {
Log.e("tag", "paramString---->null");
return str;
}
Log.e("tag","paramString:"+paramString);
int i = paramString.lastIndexOf('.');
if (i <= -1) {
Log.e("tag","i <= -1");
return str;
}
str = paramString.substring(i + 1);
Log.e("tag","paramString.substring(i + 1)------>"+str);
return str;
}
}
用到的MD5工具,文件下载的名字唯一性
package com.wjy.project.mytbs;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* Created by wjy on 2020/2/11.
*/
public class Md5Tool {
private static String bytesToHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(0xFF & bytes[i]);
if (hex.length() == 1) {
sb.append('0');
}
sb.append(hex);
}
return sb.toString();
}
public static String hashKey(String key) {
String hashKey;
try {
final MessageDigest mDigest = MessageDigest.getInstance("MD5");
mDigest.update(key.getBytes());
hashKey = bytesToHexString(mDigest.digest());
} catch (NoSuchAlgorithmException e) {
hashKey = String.valueOf(key.hashCode());
}
return hashKey;
}
}
下面的本例子中用到的网络请求 okhttp3:LoadFileModel
package com.wjy.project.mytbs;
import android.text.TextUtils;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
/**
* Created by wjy on 2020/2/11.
*/
public class LoadFileModel {
public static void loadFile(String url, Callback<ResponseBody> callback) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://www.baidu.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
LoadFileApi mLoadFileApi = retrofit.create(LoadFileApi.class);
if (!TextUtils.isEmpty(url)) {
Call<ResponseBody> call = mLoadFileApi.loadPdfFile(url);
call.enqueue(callback);
}
}
}
package com.wjy.project.mytbs;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Url;
/**
* Created by wjy on 2020/2/11.
*/
public interface LoadFileApi {
@GET
Call<ResponseBody> loadPdfFile(@Url String fileUrl);
}
到此 整个例子就结束了。
源码地址:
git:https://gitee.com/AlaYu/MyTBS
CSDN://download.csdn.net/download/u013184970/12154456