在APP端中我们有一些需求,比如我 使用 webview 展现的内容需要生成PDF,中间省略过程,最终iframe将 PDF 的base64 传给了APP。
但是在安卓APP中使用:
var Base64 = plus.android.importClass("android.util.Base64");
var bytes = Base64.decode(base64Str, Base64.DEFAULT);
如果base64长度过长会导致最终返回的 bytes 为 null
在翻查过往经验中也发现了有人出现这个问题,原因就是 因为 NativeJS 使用会有参数长度限制
问题摘自 :https://ask.dcloud.net.cn/question/93515
评论下有说使用 腾讯X5内核解决问题,但是我试了依旧不行。(可能是我使用姿势不对吧)
然后我试了最后一层大佬的想法分段字符串获取 bytes 最后合并到一起,很高兴这样也是没问题,但是因为使用 NativeJS 有性能传输损耗,实际情况导致需要加载很久。(10M的PDF 生成实际大概需要4分钟)
没办法了,看了下数据实际最后返回就是带符号的整数数组,查阅资料手动写个普通方法转(因为对原生也不熟)用于替换 Base64.decode 方法
function base64ToByteArray(base64Str) {
const binaryString = atob(base64Str);
const uint8Array = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
uint8Array[i] = binaryString.charCodeAt(i);
}
let arr = []
Array.from(uint8Array).map(num => {
arr.push(num >= 128 ? (num - 256) : num)
})
return arr;
}
最终的 base64转本地文件 方法也就出现了
/**
* base64字符串转成文件
* @param {String} base64Str // 允许包含前缀
* @param {String} fileName // 文件名称:1663061363470.xlsx
* @param {Object} callback // 返回本地路径径URL,file:///xxx/doc/1663062980631.xlsx
*/
function base64ToFile(base64Str, fileName, callback) {
// #ifdef H5
// 去除base64前缀
var index = base64Str.indexOf(',');
base64Str = base64Str.slice(index + 1, base64Str.length);
// 创建Blob对象
var blob = dataURItoBlob(base64Str);
// 创建一个新的Blob URL
var blobUrl = window.URL.createObjectURL(blob);
// 创建一个新的a标签用于下载
var a = document.createElement('a');
a.href = blobUrl;
a.download = fileName;
document.body.appendChild(a);
// 模拟点击a标签触发下载
a.click();
// 移除a标签和Blob URL
document.body.removeChild(a);
window.URL.revokeObjectURL(blobUrl);
// 回调
callback && callback(blobUrl);
// 将base64字符串转换为Blob对象
function dataURItoBlob(dataURI) {
var byteString = atob(dataURI);
var arrayBuffer = new ArrayBuffer(byteString.length);
var uint8Array = new Uint8Array(arrayBuffer);
for (var i = 0; i < byteString.length; i++) {
uint8Array[i] = byteString.charCodeAt(i);
}
return new Blob([uint8Array], {
type: 'application/octet-stream'
});
}
// #endif
// #ifdef APP-PLUS
// 去除base64前缀
var index = base64Str.indexOf(',')
var base64Str = base64Str.slice(index + 1, base64Str.length)
plus.io.requestFileSystem(plus.io.PRIVATE_DOC, function(fs) {
fs.root.getFile(fileName, {
create: true
}, function(entry) {
// 获得本地路径URL,file:///xxx/doc/1663062980631.xlsx
var fullPath = entry.fullPath;
let platform = uni.getSystemInfoSync().platform;
if (platform == 'android') {
var FileOutputStream = plus.android.importClass("java.io.FileOutputStream");
try {
function base64ToByteArray(base64Str) {
const binaryString = atob(base64Str);
const uint8Array = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
uint8Array[i] = binaryString.charCodeAt(i);
}
let arr = []
Array.from(uint8Array).map(num => {
arr.push(num >= 128 ? (num - 256) : num)
})
return arr;
}
var out = new FileOutputStream(fullPath);
let bytes = base64ToByteArray(base64Str);
if (bytes == null || bytes.length == 0) {
out.close();
uni.hideLoading();
uni.showModal({
title: "生成失败",
content: "nativeJS限制参数长度无法获取文件!",
showCancel: false
})
return
} else {
out.write(bytes);
out.close();
// 回调
callback && callback(entry.toLocalURL());
return
}
} catch (e) {
console.log(e.message);
}
} else if (platform == 'ios') {
var NSData = plus.ios.importClass('NSData');
var nsData = new NSData();
nsData = nsData.initWithBase64EncodedStringoptions(base64Str, 0);
if (nsData) {
nsData.plusCallMethod({
writeToFile: fullPath,
atomically: true
});
plus.ios.deleteObject(nsData);
}
// 回调
callback && callback(entry.toLocalURL());
}
})
})
// #endif
}
//使用参考
base64ToFile(base64Str, "123.pdf", (path) => {
uni.hideLoading();
console.log("path=>", path);
// #ifdef APP
uni.openDocument({
filePath: path,
showMenu: true,
success: function(res) {
console.log('打开文档成功');
},
fail: (err) => {
console.log(err)
this.showSPModal("提示", "文件打开失败!" + err.errMsg)
}
});
// #endif
})
好了,上面就是记录我base64转文件至本地的经验了,避免下一个人踩坑。
5 个评论
要回复文章请先登录或注册
5***@qq.com
x***@163.com
x***@163.com
1***@163.com
1***@163.com