Android之TBS浏览Word、Excel、PPT、PDF等文件

有时我们在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 

发布了92 篇原创文章 · 获赞 38 · 访问量 14万+

猜你喜欢

转载自blog.csdn.net/u013184970/article/details/104298207