集成腾讯TBS文件浏览word,excel,ppt等文件
@Author GQ 2017年01月12日
基本每个项目中有附件下载和查看功能,我这里选择腾讯TBS文件浏览服务
记录一下集成遇到的问题和心得 (由于项目使用Kotlin写的,所以截取代码片段)
效果图
- 加载了网络excel文件
介绍
一开始使用的是https://github.com/ZhongXiaoHong/superFileView
后来用着出问题了,还是自己重新写一下好了,顺便记录下来
官网
- 首先去官网下载SDK文件, tbs官网
so
放在armeabi
下jar
放在libs
下
Andorid Studio
Gradle配置
- 在
app
下的build.gradle
中
ndk {
abiFilters "armeabi", "x86"
}
XML
- 新建一个外层
RelativeLayout
,将展示文件的tbsReaderView
add进去
<RelativeLayout
android:id="@+id/rl_file"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="5dp"
android:paddingRight="5dp"/>
Kotlin
新建一个TbsFileActivity
- 实现
ReaderCallback
接口的onCallBackAction
方法,内容空着就行
class TbsFileActivity : AppCompatActivity(), TbsReaderView.ReaderCallback {
override fun onCallBackAction(p0: Int?, p1: Any?, p2: Any?) {
}
}
定义几个变量,稍后使用
//缓存文件路径 ,APK_FILE是在sd卡的生成的文件夹名称"test",CACHE为"/cache"
val cacheDir: String = Environment.getExternalStorageDirectory().absolutePath + "/" + APK_FILE + CACHE
private var mTbsReaderView: TbsReaderView? = null
private var mFileName: String = ""//eg: 哈哈.doc
OnCreate
//避免输入法界面弹出后遮挡输入光标的问题
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE or WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
...
mTbsReaderView = TbsReaderView(this, this)
rl_file.addView(mTbsReaderView, RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT))
//初始化数据
initData()
fun initData() {
//这个"path"是上一个界面传来的参数暂时忽略
filePath = intent.getSerializableExtra("path") as String
Log.e(TAG, "文件path:" + filePath);
if (filePath.isNullOrEmpty()) {
ToastUtil.showInCenter("文件不存在")
} else {
mFileName = getFileName(filePath!!)
if (isLocalExist()) {
//缓存有直接读取
displayFile(getLocalFile())
} else {
//没有请求网络
if (filePath!!.contains("http")) {
downLoadFromNet(filePath!!)
} else {
ToastUtil.showInCenter("文件链接不合法")
}
}
}
}
下载文档
- 使用OkGo
private fun downLoadFromNet(url: String) {
val cacheFile = getCacheFile(url)
if (cacheFile.exists()) {
if (cacheFile.length() <= 0) {
cacheFile.delete()
return
}
}
val myFileCallback: FileCallback = object : FileCallback(cacheDir, mFileName) {
override fun onSuccess(response: Response<File>?) {
displayFile(response?.body())
}
override fun downloadProgress(progress: Progress?) {
super.downloadProgress(progress)
}
}
OkGo.get<File>(url).execute(myFileCallback)
}
显示文档
fun displayFile(mFile: File?) {
//这里百度查到的资料
if (mFile != null && !TextUtils.isEmpty(mFile.toString())) {
//增加下面一句解决没有TbsReaderTemp文件夹存在导致加载文件失败
val bsReaderTemp = "/storage/emulated/0/TbsReaderTemp"
val bsReaderTempFile = File(bsReaderTemp)
if (!bsReaderTempFile.exists()) {
Log.e("准备创建/storage/emulated/0/TbsReaderTemp!!")
val mkdir = bsReaderTempFile.mkdir()
if (!mkdir) {
Log.e("创建/storage/emulated/0/TbsReaderTemp失败!!!!!")
}
}
//加载文件,这里的传参的key和value不需要改动
val localBundle = Bundle()
localBundle.putString("filePath", mFile.toString())
localBundle.putString("tempPath", Environment.getExternalStorageDirectory().toString() + "/" + "TbsReaderTemp")
//这步必须有,不然会报错 TbsReaderView: init Failed!
if (this.mTbsReaderView == null)
this.mTbsReaderView = getTbsReaderView(this)
val bool = this.mTbsReaderView!!.preOpen(getFileType(mFile.toString()), false)
if (bool) {
mTbsReaderView?.openFile(localBundle)
}
} else {
Log.e("文件路径无效!")
}
}
OnDestroy
public override fun onDestroy() {
super.onDestroy()
mTbsReaderView?.onStop();
}
- 上面用到的一些方法
//查看本地文件是否存在
private fun isLocalExist(): Boolean {
return getLocalFile().exists()
}
//获取本地文件
private fun getLocalFile(): File {
return File(cacheDir, mFileName)
}
//新建TbsReaderView
private fun getTbsReaderView(context: Context): TbsReaderView {
return TbsReaderView(context, this)
}
//获取缓存文件
private fun getCacheFile(url: String): File {
val cacheFile = File(cacheDir + getFileName(url))
Log.e(TAG, "缓存文件 = " + cacheFile.toString())
return cacheFile
}
//根据链接获取文件名(带类型的),具有唯一性
private fun getFileName(url: String): String {
return Md5Util.hashKey(url) + "." + getFileType(url)
}
//拼接文件类型后缀
private fun getFileType(paramString: String): String {
var str = ""
if (TextUtils.isEmpty(paramString)) {
return str
}
val i = paramString.lastIndexOf('.')
if (i <= -1) {
return str
}
str = paramString.substring(i + 1)
return str
}
- Md5Util
object Md5Util {
private fun bytesToHexString(bytes: ByteArray): String {
val sb = StringBuilder()
for (i in bytes.indices) {
val hex = Integer.toHexString(0xFF and bytes[i].toInt())
if (hex.length == 1) {
sb.append('0')
}
sb.append(hex)
}
return sb.toString()
}
fun hashKey(key: String): String {
var hashKey: String
try {
val mDigest = MessageDigest.getInstance("MD5")
mDigest.update(key.toByteArray())
hashKey = bytesToHexString(mDigest.digest())
} catch (e: NoSuchAlgorithmException) {
hashKey = key.hashCode().toString()
}
return hashKey
}
}
向外暴露 show()
方法
companion object {
var filePath: String? = null
fun show(context: Context, url: String) {
var intent = Intent(context, TbsFileUI::class.java)
val bundle = Bundle()
bundle.putSerializable("path", url)
intent.putExtras(bundle)
context.startActivity(intent)
}
}
调用Tbs页面
注意别忘了加权限配置
<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" />
Application
初始化QbSdk.initX5Environment(contxt, null); QbSdk.setDownloadWithoutWifi(true);//设置支持非Wifi下载
在其他页面调用即可
var fileUrl = "http://这里是一个网络文件地址,百度随便找一个"
fileUrl?.let { it -> TbsFileActivity.show(this, it) }