- 点击跳转=>Unity3D特效百例
- 点击跳转=>案例项目实战源码
- 点击跳转=>游戏脚本-辅助自动化
- 点击跳转=>Android控件全解手册
- 点击跳转=>Scratch编程案例
- 点击跳转=>软考全系列
👉关于作者
众所周知,人生是一个漫长的流程,不断克服困难,不断反思前进的过程。在这个过程中会产生很多对于人生的质疑和思考,于是我决定将自己的思考,经验和故事全部分享出来,以此寻找共鸣 !!!
专注于Android/Unity和各种游戏开发技巧,以及各种资源分享(网站、工具、素材、源码、游戏等)
有什么需要欢迎私我,交流群让学习不再孤单。
👉实践过程
从2023年4月开始腾讯的TBS文档进入付费和在线时代,原来的免费形式已经成为过去式,付费无可厚非,但是很容易遇到不愿意掏钱的公司,而你又在这个公司工作。所以离线文档浏览的业务还是有小众场景的。
而且即使是免费在线的他也有流控,就是当你应用有一定用户量之后,会有一定概率从中抽取必然有小部分用户让他无法下载内核,刺激付费的手段而已。除此之外,一定时间内失败次数多了后续一定时间必然失败,就好比你手机开锁忘记密码类似,还有官网维护时间,你也不能下载,等等原因。
这篇文章主要讲正常情况下离线模式的使用,搞清楚原因,下一篇文章我们将如何彻底的离线,可以以后任何项目随便用。
从2022年不知道哪个TBS版本更新,就已经开始内置付费功能以及去除了一些本地方法。所以我们使用的前提是尽量靠前点版本,比如2021年-2022年5月份的插件和功能。
最下方有完整代码。
😜准备内容
- 我们都知道在线模式集成需要下载tbs文件,大概40mb左右,所以我们就需要准备好这个,光这个我相信就难道了大部分人,因为很少有人去专门的备份这个,只能去网上搜看看谁保存过。也可以找我,我备份了7个版本。拿到这个后将后缀改为apk。
- 接着就需要准备jar包了。这个很好准备,相信很多人都有,例
tbs_sdk_thirdapp_v4.3.0.253_44153_sharewithdownloadwithfile_withoutGame_obfs_20220117_105333.jar
😜开始集成
先将jar放到libs下进行依赖,然后在Manifest中添加权限。
<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/
📢这位道友请留步☁️,我观你气度不凡,谈吐间隐隐有王者霸气💚,日后定有一番大作为📝!!!旁边有点赞👍收藏🌟今日传你,点了吧,未来你成功☀️,我分文不取,若不成功⚡️,也好回来找我。文章来源:https://www.toymoban.com/news/detail-476644.html
温馨提示:点击下方卡片获取更多意想不到的资源。
文章来源地址https://www.toymoban.com/news/detail-476644.html
到了这里,关于Android问题笔记 - 关于腾讯文档TBS离线的研究的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!