Android之腾讯TBS文件预览


前言

做Android的各位,是不是觉得移动端去搞这个文件预览很操蛋,而且还是各种文件预览,如果只是PDF可以直接搞定,要预览各种文件怎么办,不接第三方怎么弄,猝死都弄不了的,相信我,来吧,今天就是为这个问题来的。


一、效果图

还是老样子,先来张效果图稳定军心。
在这里插入图片描述

二、实现步骤

1.去官网注册并创建应用腾讯官网

在这里插入图片描述

2.下载arr文件并引入腾讯TBS

代码如下(示例):

//腾讯TBS文件预览
implementation fileTree(dir: 'libs', include: ['TbsFileSdk_base_arm64_1.0.5.6000094.20250604183426.aar'])

3.application实例化

代码如下(示例):

//腾讯TBS初始化
    fun initEngineAsync() {
        //设置 licenseKey
        TbsFileInterfaceImpl.setLicenseKey("你自己的licensekey")

        val callback: ITbsReaderCallback = object : ITbsReaderCallback {
            override fun onCallBackAction(actionType: Int, args: Any, result: Any) {
                println("初始化actionType=$actionType,args=$args,result=$result")
                // ITbsReader.OPEN_FILEREADER_ASYNC_LOAD_READER_ENTRY_CALLBACK 的值为7002,不是错误码
                if (ITbsReader.OPEN_FILEREADER_ASYNC_LOAD_READER_ENTRY_CALLBACK === actionType) {
                    val ret = args as Int // 错误码为 actionType == 7002时 args 的值
                    if (ret == 0) {
                        // 初始化成功
                        println("初始化成功了-----")
                    } else {
                        // 初始化失败
                        println("初始化失败了-----")
                    }
                }
            }
        }
        if (!TbsFileInterfaceImpl.isEngineLoaded()) {
            TbsFileInterfaceImpl.initEngineAsync(this, callback)
        }
    }

4.activity实例化

代码如下(实例化成功才能有后续哦):

//定义变量
private var isInit = false
//实例化
var ret = initEngine(this)
  if (ret == 0) {
     println("初始化成功--->界面")
   isInit = true
   } else {
      println("初始化失败--->界面")
   }

5.下载网络文件

//docurl下载文件地址,filename本地存储路径,endname文件格式
 fun download(docUrl: String, fileName: String, endName: String) {
        DialogUtils.showLoadingDialog(this)
        val filePath =
            getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString() + "/" + fileName // 本地存储路径
        // 下载文件(可以使用 OkHttp、Retrofit 或原生 HttpURLConnection)
        Thread {
            try {
                val url = URL(docUrl)
                val connection: HttpURLConnection = url.openConnection() as HttpURLConnection
                connection.setRequestMethod("GET")
                connection.setDoInput(true)
                connection.connect()

                val file = File(filePath)
                if (!file.exists()) {
                    file.createNewFile()
                }

                connection.getInputStream().use { `in` ->
                    FileOutputStream(file).use { out ->
                        val buffer = ByteArray(1024)
                        var len: Int
                        while ((`in`.read(buffer).also { len = it }) != -1) {
                            out.write(buffer, 0, len)
                        }
                        out.flush()
                    }
                }
                // 下载完成后,在主线程打开文件
                runOnUiThread {
                    openExternalFilesDirDocument(filePath, endName)
                    DialogUtils.hideLoadingDialog()
                }
            } catch (e: Exception) {
                e.printStackTrace()
                runOnUiThread {
                    ToastUtils.showToast("下载失败")
                }
            }
        }.start()
    }

//打开预览
    private fun openExternalFilesDirDocument(filePath: String, extName: String) {
        if (isInit) {
            if (TbsFileInterfaceImpl.canOpenFileExt(extName)) {
                startActivity(
                    Intent(this, PreviewActivity::class.java).putExtra(
                        "filePath",
                        filePath
                    ).putExtra("fileExt", extName).putExtra("url", zhlist[0])
                )
                finish()
            } else {
                ToastUtils.showToast("此类型文档暂不支持打开")
                // tbs 不支持打开的类型
            }
        } else {
            Toast.makeText(
                applicationContext,
                "Engine未初始化成功,无法打开文件",
                Toast.LENGTH_SHORT
            ).show()
        }
    }

6.PreviewActivity预览

class PreviewActivity : BaseActivity() {
    private lateinit var mFlRoot: FrameLayout
    private lateinit var mRl: RelativeLayout
    private var isDestroyed = false
    private lateinit var imag_fh: ImageView
    private lateinit var relaitve_xyb: RelativeLayout

    override fun getContentViewId(): Int {
        return R.layout.preview
    }

    override fun initView(savedInstanceState: Bundle?) {
        mFlRoot = findViewById(R.id.content)
        mRl = findViewById(R.id.reader_top)
        imag_fh = findViewById(R.id.imag_fh)
        relaitve_xyb = findViewById(R.id.relaitve_xyb)
        imag_fh.setOnClickListener(this)
        relaitve_xyb.setOnClickListener(this)
        val filePath = intent.getStringExtra("filePath").toString()
        val fileExt = intent.getStringExtra("fileExt").toString()
        openFile(filePath, fileExt)
    }

    override fun onClick(v: View?) {
        when (v?.id) {
            R.id.imag_fh -> finish()
            //下载
            R.id.relaitve_xyb -> {
                downloadFile(this, intent.getStringExtra("url").toString(), "下载文档")
            }
        }
    }

    fun downloadFile(context: Context, url: String?, fileName: String?) {
        val downloadManager = context.getSystemService(DOWNLOAD_SERVICE) as DownloadManager
        val uri = Uri.parse(url)
        val request = DownloadManager.Request(uri)
        // 设置通知栏提示(下载中、完成)
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
        // 设置保存路径(Android 10+ 需使用 MediaStore API 或保存到 Downloads 目录)
        request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName)
        // 发起下载
        downloadManager.enqueue(request)
        ToastUtils.showToast("已开始下载,请注意导航栏下载进度")
    }

    fun openFile(filePath: String, fileExt: String) {
        //设置回调
        val callback =
            ITbsReaderCallback { actionType, args, result ->
                println("actionType=$actionType,args=$args,result=$result")
                if (ITbsReader.OPEN_FILEREADER_STATUS_UI_CALLBACK == actionType) {
                    if (args is Bundle) {
                        val id = (args as Bundle).getInt("typeId")
                        if (ITbsReader.TBS_READER_TYPE_STATUS_UI_SHUTDOWN == id) {
                            finish() // 加密文档弹框取消需关闭 activity
                        }
                    }
                }
            }

        //设置参数
        val param = Bundle()
        param.putString("filePath", filePath)
        param.putString("fileExt", fileExt) // 文件后缀名,如文件名为 test.pdf,则只需要传入"pdf"
        param.putString("tempPath", getExternalFilesDir("temp")!!.absolutePath)

        //调用openFileReader打开文件
        mFlRoot.post {
            val height = mFlRoot.height
            // 自定义 layout 模式必须设置这个值,否则可能导致文档内容显示不全
            param.putInt("set_content_view_height", height)
            val ret = TbsFileInterfaceImpl.getInstance().openFileReader(
                this@PreviewActivity, param, callback, mFlRoot
            )
        }
    }

    // 销毁资源使用 onpause + ondestroy 的方式。避免 onDestroy 延迟回调
    private fun destroy() {
        if (isDestroyed) {
            return
        }
        // 回收资源
        mFlRoot.removeAllViews() //移除内容显示区域 layout
        TbsFileInterfaceImpl.getInstance().closeFileReader() //关闭 fileReader
        isDestroyed = true
    }

    override fun onPause() {
        super.onPause()
        if (isFinishing) {
            destroy()
        }
    }

    public override fun onDestroy() {
        super.onDestroy()
        destroy()
    }

    //横竖屏切换
    override fun onConfigurationChanged(@NonNull newConfig: Configuration) {
        super.onConfigurationChanged(newConfig)
        mFlRoot.viewTreeObserver.addOnGlobalLayoutListener(object : OnGlobalLayoutListener {
            override fun onGlobalLayout() {
                mFlRoot.viewTreeObserver.removeOnGlobalLayoutListener(this)
                val w = mFlRoot.width
                val h = mFlRoot.height
                TbsFileInterfaceImpl.getInstance().onSizeChanged(w, h)
            }
        })
    }
}

7.preview布局

<?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"
    android:background="@color/backColor"
    android:orientation="vertical">

    <FrameLayout
        android:id="@+id/content"
        android:layout_width="match_parent"
        android:layout_below="@+id/reader_top"
        android:layout_height="match_parent"/>
    <RelativeLayout
        android:id="@+id/relaitve_xyb"
        android:layout_width="240dp"
        android:layout_height="48dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="10dp">

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="fitXY"
            android:src="@mipmap/scmbback" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="下载"
            android:textColor="#ffffff"
            android:textSize="16dp" />
    </RelativeLayout>
</RelativeLayout>

总结

到此结束就解决了Android文件预览问题,如果有疑问随时评论区见。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叶已初秋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值