Android问题笔记 - 关于腾讯文档TBS离线的研究

这篇具有很好参考价值的文章主要介绍了Android问题笔记 - 关于腾讯文档TBS离线的研究。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

专栏分享
  • 点击跳转=>Unity3D特效百例
  • 点击跳转=>案例项目实战源码
  • 点击跳转=>游戏脚本-辅助自动化
  • 点击跳转=>Android控件全解手册
  • 点击跳转=>Scratch编程案例
  • 点击跳转=>软考全系列

👉关于作者

众所周知,人生是一个漫长的流程,不断克服困难,不断反思前进的过程。在这个过程中会产生很多对于人生的质疑和思考,于是我决定将自己的思考,经验和故事全部分享出来,以此寻找共鸣 !!!
专注于Android/Unity和各种游戏开发技巧,以及各种资源分享(网站、工具、素材、源码、游戏等)
有什么需要欢迎私我,交流群让学习不再孤单

Android问题笔记 - 关于腾讯文档TBS离线的研究

👉实践过程

从2023年4月开始腾讯的TBS文档进入付费和在线时代,原来的免费形式已经成为过去式,付费无可厚非,但是很容易遇到不愿意掏钱的公司,而你又在这个公司工作。所以离线文档浏览的业务还是有小众场景的。
而且即使是免费在线的他也有流控,就是当你应用有一定用户量之后,会有一定概率从中抽取必然有小部分用户让他无法下载内核,刺激付费的手段而已。除此之外,一定时间内失败次数多了后续一定时间必然失败,就好比你手机开锁忘记密码类似,还有官网维护时间,你也不能下载,等等原因。
这篇文章主要讲正常情况下离线模式的使用,搞清楚原因,下一篇文章我们将如何彻底的离线,可以以后任何项目随便用。
从2022年不知道哪个TBS版本更新,就已经开始内置付费功能以及去除了一些本地方法。所以我们使用的前提是尽量靠前点版本,比如2021年-2022年5月份的插件和功能。

最下方有完整代码。

😜准备内容

  1. 我们都知道在线模式集成需要下载tbs文件,大概40mb左右,所以我们就需要准备好这个,光这个我相信就难道了大部分人,因为很少有人去专门的备份这个,只能去网上搜看看谁保存过。也可以找我,我备份了7个版本。拿到这个后将后缀改为apk。
  2. 接着就需要准备jar包了。这个很好准备,相信很多人都有,例
    tbs_sdk_thirdapp_v4.3.0.253_44153_sharewithdownloadwithfile_withoutGame_obfs_20220117_105333.jar

😜开始集成

先将jar放到libs下进行依赖,然后在Manifest中添加权限。
Android问题笔记 - 关于腾讯文档TBS离线的研究

<uses-permission android:name="android.permission.INTERNET" />
<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.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
    tools:ignore="ProtectedPermissions" />
<!--SDCard中创建与删除文件权限 -->
<uses-permission
    android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
tools:ignore="ProtectedPermissions" />

之后打开我们的Activity,添加代码将我们改过tbs后缀的apk用代码赋值到指定目录,记得是指定目录,刚开始我也以随意目录都可以,但是测试了多款机型发现并非如此。只有在这个目录jar包的静态安装代码才能保证100%正确识别到。规则是:
/storage/emulated/0/Android/data/你的应用包名/下。
注:记得动态权限申请,我写Demo嫌麻烦直接从手机设置里自己打开的。

拷贝完成后要进行installLocalTbsCore代码安装,

FileUtils.copyAssets(getApplicationContext(), "046007_x5.tbs.apk", FileUtils.getTBSFileDir(getApplicationContext()).getPath() + "/046007_x5.tbs.apk");
if (!QbSdk.canLoadX5(getApplicationContext())) {
    QbSdk.reset(getApplicationContext());
    QbSdk.installLocalTbsCore(getApplicationContext(), 46007, FileUtils.getTBSFileDir(getApplicationContext()).getPath() + "/046007_x5.tbs.apk");
}
HashMap<String, Object> map = new HashMap<>(2);
map.put(TbsCoreSettings.TBS_SETTINGS_USE_SPEEDY_CLASSLOADER, true);
map.put(TbsCoreSettings.TBS_SETTINGS_USE_DEXLOADER_SERVICE, true);
QbSdk.initTbsSettings(map);
QbSdk.setTbsListener(new TbsListener() {
    @Override
    public void onDownloadFinish(int i) {
        Log.e("TAG", "进行了tbs:onDownloadFinish " + i);
    }

    @Override
    public void onInstallFinish(int i) {
        Log.e("TAG", "进行了tbs:onInstallFinish " + i);
    }

    @Override
    public void onDownloadProgress(int i) {
        Log.e("TAG", "进行了tbs:onDownloadProgress " + i);
    }
});

记得调用下reset,删除所有相关的tbs内容,确保必然成功。
这样基本就可以安装完毕,记得调用安装代码延迟一点时间,因为拷贝资源需要一两秒时间。
安装完毕后你可以在设备大data/data/包名目录下看到增加了很多tbs的内容,利用Android Studio的Device File Explorer可以看到。
大家以为安装完这个打开文件就行了?
并不是,又被坑了一把,原来在线集成都是随意传递个路径就可以,但是这种离线的想要打开文档还得放到指定目录下,这点要格外注意。

打开文件需要你将文件拷贝的指定目录
FileUtils.copyAssets(getApplicationContext(), “config”, FileUtils.getTBSFileDir(getApplicationContext()).getPath());

之后打开文件的代码也需要是这个目录才可以。详情看附录全部代码。
问题又来了,你仔细观察打开的瞬间,会发现竟然还在下载东西,没错那是对应文档类型的真正解析渲染插件。那这也算不上离线啊,不要急我们下篇文章见分晓。彻底意义上的离线。

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private Button idDebugBtnFileDocx, idDebugBtnFileDoc, idDebugBtnFileXlsx, idDebugBtnFileXls, idDebugBtnFilePdf, idDebugBtnFilePptx,
            idDebugBtnFilePpt, idDebugBtnFileTxt, idDebugBtnFileEpub, idDebugBtnFilePng;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        idDebugBtnFileDocx = findViewById(R.id.idDebugBtnFileDocx);
        idDebugBtnFileDocx.setOnClickListener(this);
        idDebugBtnFileDoc = findViewById(R.id.idDebugBtnFileDoc);
        idDebugBtnFileDoc.setOnClickListener(this);
        idDebugBtnFileXlsx = findViewById(R.id.idDebugBtnFileXlsx);
        idDebugBtnFileXlsx.setOnClickListener(this);
        idDebugBtnFileXls = findViewById(R.id.idDebugBtnFileXls);
        idDebugBtnFileXls.setOnClickListener(this);
        idDebugBtnFilePdf = findViewById(R.id.idDebugBtnFilePdf);
        idDebugBtnFilePdf.setOnClickListener(this);
        idDebugBtnFilePptx = findViewById(R.id.idDebugBtnFilePptx);
        idDebugBtnFilePptx.setOnClickListener(this);
        idDebugBtnFilePpt = findViewById(R.id.idDebugBtnFilePpt);
        idDebugBtnFilePpt.setOnClickListener(this);
        idDebugBtnFileTxt = findViewById(R.id.idDebugBtnFileTxt);
        idDebugBtnFileTxt.setOnClickListener(this);
        idDebugBtnFileEpub = findViewById(R.id.idDebugBtnFileEpub);
        idDebugBtnFileEpub.setOnClickListener(this);
        idDebugBtnFilePng = findViewById(R.id.idDebugBtnFilePng);
        idDebugBtnFilePng.setOnClickListener(this);
        FileUtils.copyAssets(getApplicationContext(), "046007_x5.tbs.apk", FileUtils.getTBSFileDir(getApplicationContext()).getPath() + "/046007_x5.tbs.apk");
        FileUtils.copyAssets(getApplicationContext(), "config", FileUtils.getTBSFileDir(getApplicationContext()).getPath());
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.e("TAG", "安装流程: " + QbSdk.canLoadX5(getApplicationContext()) + "==" + getFileIsExists("046007_x5.tbs.apk"));
        if (!QbSdk.canLoadX5(getApplicationContext())) {
            QbSdk.reset(getApplicationContext());
            QbSdk.installLocalTbsCore(getApplicationContext(), 46007, FileUtils.getTBSFileDir(getApplicationContext()).getPath() + "/046007_x5.tbs.apk");
        }
        HashMap<String, Object> map = new HashMap<>(2);
        map.put(TbsCoreSettings.TBS_SETTINGS_USE_SPEEDY_CLASSLOADER, true);
        map.put(TbsCoreSettings.TBS_SETTINGS_USE_DEXLOADER_SERVICE, true);
        QbSdk.initTbsSettings(map);
        QbSdk.setTbsListener(new TbsListener() {
            @Override
            public void onDownloadFinish(int i) {
                Log.e("TAG", "进行了tbs:onDownloadFinish " + i);
            }

            @Override
            public void onInstallFinish(int i) {
                Log.e("TAG", "进行了tbs:onInstallFinish " + i);
            }

            @Override
            public void onDownloadProgress(int i) {
                Log.e("TAG", "进行了tbs:onDownloadProgress " + i);
            }
        });
    }

    public static boolean getFileIsExists(String fileName) {
        File file = new File(Environment.getExternalStorageDirectory(), fileName);
        // 如果文件不存在
        if (file.exists()) {
            return true;
        }
        return false;
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.idDebugBtnFileDocx:
                FileLookActivity.path = FileUtils.getTBSFileDir(getApplicationContext()).getPath() + "/doc插件.docx";
                startActivity(new Intent(this, FileLookActivity.class));
                break;
            case R.id.idDebugBtnFileDoc:
                FileLookActivity.path = FileUtils.getTBSFileDir(getApplicationContext()).getPath() + "/doc插件 - 副本.doc";
                startActivity(new Intent(this, FileLookActivity.class));
                break;
            case R.id.idDebugBtnFileXlsx:
                FileLookActivity.path = FileUtils.getTBSFileDir(getApplicationContext()).getPath() + "/xls插件.xlsx";
                startActivity(new Intent(this, FileLookActivity.class));
                break;
            case R.id.idDebugBtnFileXls:
                FileLookActivity.path = FileUtils.getTBSFileDir(getApplicationContext()).getPath() + "/xls插件 - 副本.xls";
                startActivity(new Intent(this, FileLookActivity.class));
                break;
            case R.id.idDebugBtnFilePdf:
                FileLookActivity.path = FileUtils.getTBSFileDir(getApplicationContext()).getPath() + "/pdf插件.pdf";
                startActivity(new Intent(this, FileLookActivity.class));
                break;
            case R.id.idDebugBtnFilePptx:
                FileLookActivity.path = FileUtils.getTBSFileDir(getApplicationContext()).getPath() + "/ppt插件.pptx";
                startActivity(new Intent(this, FileLookActivity.class));
                break;
            case R.id.idDebugBtnFilePpt:
                FileLookActivity.path = FileUtils.getTBSFileDir(getApplicationContext()).getPath() + "/ppt插件 - 副本.ppt";
                startActivity(new Intent(this, FileLookActivity.class));
                break;
            case R.id.idDebugBtnFileTxt:
                FileLookActivity.path = FileUtils.getTBSFileDir(getApplicationContext()).getPath() + "/txt插件.txt";
                startActivity(new Intent(this, FileLookActivity.class));
                break;
            case R.id.idDebugBtnFileEpub:
                FileLookActivity.path = FileUtils.getTBSFileDir(getApplicationContext()).getPath() + "/猫哥聊.epub";
                startActivity(new Intent(this, FileLookActivity.class));
                break;
            case R.id.idDebugBtnFilePng:
                FileLookActivity.path = FileUtils.getTBSFileDir(getApplicationContext()).getPath() + "/微信-空名先生_2023-03-27_16-07-53.png";
                startActivity(new Intent(this, FileLookActivity.class));
                break;
            default:
                break;
        }
    }
}


public class FileUtils {

    /**
     * 保存文件预览的目录
     *
     * @param context 上下文对象
     */
    public static File getTBSFileDir(Context context) {
        String dirName = "TBSFile";
        return context.getExternalFilesDir(dirName);
    }

    /**
     * 把asset的文件转化为本地文件
     *
     * @param context 上下文对象
     * @param oldPath 旧的文件路径
     * @param newPath 新的文件路径
     */
    public static boolean copyAssets(Context context, String oldPath, String newPath) {
        try {
            String fileNames[] = context.getAssets().list(oldPath);// 获取assets目录下的所有文件及目录名
            if (fileNames.length > 0) {// 如果是目录
                File file = new File(newPath);
                file.mkdirs();// 如果文件夹不存在,则递归
                for (String fileName : fileNames) {
                    Log.e("TAG", "正在进行拷贝: "+fileName);
                    copyAssets(context, oldPath + "/" + fileName, newPath + "/" + fileName);
                }
            } else {// 如果是文件
                InputStream is = context.getAssets().open(oldPath);
                FileOutputStream fos = new FileOutputStream(new File(newPath));
                byte[] buffer = new byte[1024];
                int byteCount;
                while ((byteCount = is.read(buffer)) != -1) {// 循环从输入流读取
                    // buffer字节
                    fos.write(buffer, 0, byteCount);// 将读取的输入流写入到输出流
                }
                fos.flush();// 刷新缓冲区
                is.close();
                fos.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 获取url文件后缀
     *
     * @param url 文件链接
     */
    public static String getSuffix(String url) {
        if ((url != null) && (url.length() > 0)) {
            int dot = url.lastIndexOf('.');
            if ((dot > -1) && (dot < (url.length() - 1))) {
                return url.substring(dot + 1);
            }
        }
        return "";
    }
}


public class FileLookActivity extends FragmentActivity {
    public static String path = "";
    private TbsReaderView mTbsReaderView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.aty_filelook);
        RelativeLayout mFlRoot = findViewById(R.id.fl_container);
        Log.e("TAG", ":文件地址"+path+MainActivity.getFileIsExists("猫哥聊.epub"));
        String bsReaderTemp = FileUtils.getTBSFileDir(FileLookActivity.this) + "/TbsReaderTemp";
        File bsReaderTempFile = new File(bsReaderTemp);
        if (!bsReaderTempFile.exists()) {
            Log.e("TAG", "准备创建/storage/emulated/0/TbsReaderTemp!!");
            boolean mkdir = bsReaderTempFile.mkdir();
            if (!mkdir) {
                Log.e("TAG", "创建/storage/emulated/0/TbsReaderTemp失败!!!!!");
            }
        }
        TbsReaderView.ReaderCallback readerCallback = new TbsReaderView.ReaderCallback() {
            @Override
            public void onCallBackAction(Integer integer, Object o, Object o1) {

            }
        };
        //回调结果参考 TbsReaderView.ReaderCallback
        //2、创建TbsReaderView
        mTbsReaderView = new TbsReaderView(this, readerCallback);
        //3、将TbsReaderView 添加到RootLayout中(可添加到自定义标题栏的下方)
        mFlRoot.addView(
                mTbsReaderView,
                new RelativeLayout.LayoutParams(
                        RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT
                )
        );
        //4、传入指定参数
        Bundle bundle =new Bundle();
        bundle.putString(TbsReaderView.KEY_FILE_PATH, path);
        bundle.putString(TbsReaderView.KEY_TEMP_PATH, FileUtils.getTBSFileDir(this) + "/" + "TbsReaderTemp");
        boolean result = mTbsReaderView.preOpen(getFileTypeDot(path), false);
        if (result) {
            //6、调用openFile打开文件
            mTbsReaderView.openFile(bundle);
        } else {
            Log.e("TAG", ":加载失败,联网重启应用进行下载 ");
        }
    }

    public static String getFileTypeDot(String filename) {
        if ((filename != null) && (filename.length() > 0)) {
            int dot = filename.lastIndexOf('.');
            if ((dot > -1) && (dot < (filename.length() - 1))) {
                return filename.substring(dot + 1);
            }
        }
        return null;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mTbsReaderView != null) {
            mTbsReaderView.onStop();
        }
    }
}

👉其他

📢作者:小空和小芝中的小空
📢转载说明-务必注明来源:https://zhima.blog.csdn.net/
📢这位道友请留步☁️,我观你气度不凡,谈吐间隐隐有王者霸气💚,日后定有一番大作为📝!!!旁边有点赞👍收藏🌟今日传你,点了吧,未来你成功☀️,我分文不取,若不成功⚡️,也好回来找我。

温馨提示点击下方卡片获取更多意想不到的资源。
Android问题笔记 - 关于腾讯文档TBS离线的研究文章来源地址https://www.toymoban.com/news/detail-476644.html

到了这里,关于Android问题笔记 - 关于腾讯文档TBS离线的研究的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 自己搭一个离线的文本描述生成图片系统

    二话不说先上效果图:(附带代码和模型资源文件)  让它画一个超级汽车在海边。。  近期百度推出了文言一心, 一个能回答问题,能根据文字描述绘制图片的服务,前期可能不太完善出现了一些失误,不过这个idea还是相当不错的   这个东西挺好哈,作为文学创作,生成

    2023年04月08日
    浏览(32)
  • 完全离线的OCR图片转文字识别工具Umi-OCR

    OCR图片转文字识别软件,完全离线。截屏/批量导入图片,支持多国语言、合并段落、竖排文字。可排除水印区域,提取干净的文本。基于 PaddleOCR 。 免费:本项目所有代码开源,完全免费。 方便:解压即用,离线运行,无需网络。 批量:可批量导入处理图片,结果保存到本

    2024年02月03日
    浏览(78)
  • 安防监控视频云存储平台EasyNVR通道频繁离线的原因排查与解决

    安防视频监控汇聚EasyNVR视频集中存储平台,是基于RTSP/Onvif协议的安防视频平台,可支持将接入的视频流进行全平台、全终端分发,分发的视频流包括RTSP、RTMP、HTTP-FLV、WS-FLV、HLS、WebRTC等格式。为了满足用户的集成与二次开发需求,我们也提供了丰富的API接口供用户调用。有

    2024年02月12日
    浏览(76)
  • 【FAQ】安防监控视频云存储平台EasyNVR频繁离线的原因排查与解决

    有用户反馈,在使用EasyNVR时会出现通道频繁离线的情况。针对该反馈我们立即进行了排查。 安防视频监控汇聚EasyNVR视频集中存储平台,是基于RTSP/Onvif协议的安防视频平台,可支持将接入的视频流进行全平台、全终端分发,分发的视频流包括RTSP、RTMP、HTTP-FLV、WS-FLV、HLS、W

    2024年02月12日
    浏览(136)
  • 服务器数据恢复—EVA存储raid5硬盘离线的数据恢复案例

    服务器数据恢复环境: 某品牌EVA某型号存储,底层是RAID5阵列,划分了若干lun。 服务器故障分析: 该存储设备中raid5阵列有两块硬盘掉线,存储中的lun丢失。 将故障服务器存储中的所有磁盘编号后取出,硬件工程师检测后发现掉线硬盘不存在物理故障,也没有发现坏道,都

    2024年01月24日
    浏览(41)
  • 服务器数据恢复-热备盘同步过程中硬盘离线的RAID5数据恢复案例

    服务器数据恢复环境: 华为OceanStor某型号存储,11块硬盘组建了一组RAID5阵列,另外1块硬盘作为热备盘使用。基于RAID5阵列的LUN分配给linux系统使用,存放Oracle数据库。 服务器故障: RAID5阵列1块硬盘由于未知原因离线,热备盘激活开始同步数据,在热备盘同步的过程中又有

    2024年02月07日
    浏览(41)
  • elasticsearch 内网下如何以离线的方式上传任意的huggingFace上的NLP模型(国内避坑指南)

            es自2020年的8.x版本以来,就提供了机器学习的能力。我们可以使用es官方提供的工具eland,将hugging face上的NLP模型,上传到es集群中。利用es的机器学习模块,来运维部署管理模型。配合es的管道处理,来更加便捷的处理数据。         但是在国内操作,根据官方文档

    2024年02月05日
    浏览(88)
  • android webview 打开腾讯文档不跳转到申请权限界面显示ERR_UNKNOWN_URL_SCHEME

    webview 只识别https和http开头的地址 webview调用setWebViewClient方法,重写shouldOverrideUrlLoading方法,返回return super.shouldOverrideUrlLoading(view, url);就可以跳转到申请权限界面了,要登录QQ去申请权限的时候报错,因为这里会返回一个带intent://的地址,只能跳转到外部。要设置 以下是具体

    2024年02月06日
    浏览(45)
  • 在离线的arm架构kylin v10服务器上使用Kuboard-Spray搭建K8S集群

    在离线的arm架构kylin v10服务器上使用Kuboard-Spray搭建K8S集群 在内网项目中需要安装K8S集群,经过调研,选择使用Kuboard-Spray工具搭建K8S集群,降低学习成本,提高安装效率。 为了简化安装使用集群的过程,搭建了私有yum源仓库和harbor私有镜像仓库。 详细参考文章: 本地yum源仓

    2024年04月10日
    浏览(50)
  • 关于微信小程序调用H5腾讯地图API获取定位信息提示失败问题--解决办法之一

    在跳转到H5页面加载腾讯地图API获取定位信息时,“真机调试”、“开发模式”都可以使用 web-view 组件访问我需要的路径。只有“体验版”、“线上版本”会出现这个错误提示。正常加载都是正常的,但是因为腾讯地图API在获取定位信息的同时,会在页面上内嵌一个隐藏的

    2024年04月26日
    浏览(57)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包