HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

uniCloud支付宝小程序云版服务空间公测结束公告

uniCloud

尊敬的uniCloud开发者,您好!

uniCloud支付宝小程序云版服务空间即将于2024年2月7号00:00正式结束公测,转为商业化发布。

商业化之后将不再提供3个月免费额度,公测期限内已领取的客户不会受到影响。
后续会涉及产品相关功能的收费,为了用户更好的体验及试用本产品,我们依然提供免费版产品,提供一定的免费额度供开发者使用,具体的收费及免费额度请查看产品文档

即付费套餐的“0元购”活动即将结束,现有的套餐版本及计费方式并没有变化,仍是基础套餐(支持免费版)+ 按量计费的模式。

如需开通本产品,请前往uniCloud控制台直接开通即可。

继续阅读 »

尊敬的uniCloud开发者,您好!

uniCloud支付宝小程序云版服务空间即将于2024年2月7号00:00正式结束公测,转为商业化发布。

商业化之后将不再提供3个月免费额度,公测期限内已领取的客户不会受到影响。
后续会涉及产品相关功能的收费,为了用户更好的体验及试用本产品,我们依然提供免费版产品,提供一定的免费额度供开发者使用,具体的收费及免费额度请查看产品文档

即付费套餐的“0元购”活动即将结束,现有的套餐版本及计费方式并没有变化,仍是基础套餐(支持免费版)+ 按量计费的模式。

如需开通本产品,请前往uniCloud控制台直接开通即可。

收起阅读 »

px rem 转换小工具

HBuilderX插件

我把小工具vscode-px-to-rem移植到了hbuilder里,有需要可以试试

我把小工具vscode-px-to-rem移植到了hbuilder里,有需要可以试试

plus.sqlite 真机调试时候insert语句报错

uniapp plus SQLite
{  
    "code": -1404,  
    "message": "android.database.sqlite.SQLiteException: no such column: 张三 (code 1 SQLITE_ERROR): , while compiling: insert into area_001 (id, bianma, name) values (1,11,张三);,https://ask.dcloud.net.cn/article/282"  
}

在真机基座调试的时候报错的,表格已经建立好了,但是插入不了数据。
这个是我的sql语句
insert into area_001 (id, bianma, name) values (1,11,张三);
请问这是语法错了吗? 为什么会找 张三 这个字段,我的sql语句不是指定name是字段,张三是值吗?

继续阅读 »
{  
    "code": -1404,  
    "message": "android.database.sqlite.SQLiteException: no such column: 张三 (code 1 SQLITE_ERROR): , while compiling: insert into area_001 (id, bianma, name) values (1,11,张三);,https://ask.dcloud.net.cn/article/282"  
}

在真机基座调试的时候报错的,表格已经建立好了,但是插入不了数据。
这个是我的sql语句
insert into area_001 (id, bianma, name) values (1,11,张三);
请问这是语法错了吗? 为什么会找 张三 这个字段,我的sql语句不是指定name是字段,张三是值吗?

收起阅读 »

个推数智运营:用数据和算法驱动APP运营增长


在较早迈入数字化进程的互联网行业,企业已经积累了大量的数据资源。如何将数据资源转化成数据资产,用数据驱动运营策略优化、产品体验升级和业务增长,是当下很多互联网企业的关注热点。

个推推出的“数智运营服务”,就是旨在帮助APP实现“让数好用,把数用好”,用数据驱动APP运营增长。它的“增长力”也在具体的实践中得到验证,已经成功帮助社交、影音等多个行业的APP客户实现运营效率和效果的双双提升。

新年新气象,APP运营也要挖掘和把握新的增长点。本文用5个关键词,带大家解锁个推数智运营服务的强劲“增长力”,希望给广大APP带来创新的运营思路,在新的一年收获全新增长!

                                                                                                                关键词一  

                                                                                                              #数智融合  

这里的融合包含两个层面的含义:

其一,是指数据层面的融合。丰富的数据是企业开展数智运营的前提,很多互联网企业在通过APP给用户提供服务的同时,还构建了小程序、Web、H5等多元形态的产品矩阵,这就需要企业将APP端数据和其他渠道的数据融合起来;此外在用户画像构建、行为特征分析等场景下,企业有时还需要借助“他山之石”,融合个推等服务商的端外数据能力,构建坚实、丰富的数据底层,才能支撑复杂的分析需求。

其二,是指经验和能力的融合。个推数智运营服务本身就是个推数智能力、产品工具和运营经验的深度融合,其定位不仅仅是解决APP运营单点问题的一款工具或产品,而是作为整体解决方案,为APP进行用户生命周期管理的各个垂直场景增能,助力APP提升关键运营指标,最终实现破局增长和运营进阶。

需要强调的是,其实APP本身就有很多运营经验和能力的积累,并且这些经验和能力已经在实际的业务场景中得到测试和验证。因此个推数智运营服务也注重将自身在移动互联网运营领域的用数经验与APP自身的运营经验融合。在服务APP客户的过程中,个推的数据专家、运营专家和APP的运营负责人、增长负责人一起,聚焦具体的场景问题,共同探寻以数据为驱动的、切实有效的运营增长方案。

                                                                                                            关键词二  

                                                                                                           #链路打通  

在实现融合的基础上,个推数智运营服务还打通了APP运营的数据流和业务流,将APP整个运营链路上从用户洞察、分层到人群圈选再到用户触达等各个环节串联起来,构建以数据为驱动的运营增长闭环。


通过个推数智运营服务,APP能够一站式地完成日常运营工作,让运营工作更丝滑、更高效,从而把更多的精力放在具体的运营场景中,并快速运用数据精准量化和分析运营效果,指导运营策略的优化。

                                                                                                          关键词三  

                                                                                                          #聚焦场景  

上文提到,个推数智运营服务融合了个推这十余年来服务数十万APP过程中所积累的丰富运营经验。个推将这些经验产品化、服务化,以规则标签、算法模型、策略模板等形式,让更多的APP客户能够直接“拿来即用”,快速解决运营难题。

目前,个推已经在用户触达、新用户冷启动、沉默用户促活、付费用户预测、流失用户预测、用户卸载分析等运营场景重点发力,和行业客户一起探索如何用好数据来实现用户生命周期的延长和商业转化上的增长。

比如,在用户触达场景,个推将大数据标签能力和算法模型能力融入到消息推送服务中,让APP能够自主圈选处于不同生命周期阶段、具有差异化兴趣偏好的细分人群,实现精细化用户触达和生命周期管理;

尤其是在付费用户预测场景,个推融合APP端内数据构建付费预测模型,通过look-alike扩量,帮助APP圈选出高潜力付费人群,实现定向转化引导,从而提升APP的商业变现能力。

                                                                                                        关键词四  

                                                                                                       #增能提效  

目前个推已经和咪咕视频、苏e行、心动日常、快音、TT语音等多个行业的APP客户合作开展数智运营实践,并取得了显著成效。

比如,助力咪咕视频实现精细化用户触达和智能内容推荐,使用户活跃和留存大幅提升;输出人群画像分析能力,助力苏e行APP实现精细化用户洞察,使新用户留存率提升23%;通过付费预测模型,助力心动日常APP挖掘高潜付费用户,使会员付费转化率提升8%;输出端外数据洞察能力,助力快音APP精细化用户分层和触达,使消息推送点击率提升150%;通过文案圈人模型,助力TT语音智能匹配文案和人群,使消息推送点击率提升120%。


关键词五

                                                                                                       #行业共创  

在运营增长方面,不同行业的APP遇到的痛点、难点,既有差异化的部分,也有很多共性的部分。2023年个推以“数据驱动运营增长”为主题,聚集了多位行业内的资深运营专家,以及来自芒果TV、网易云音乐、哈啰出行、携程智行火车票、萌宝公司等知名互联网企业的APP增长官,分享运营实践经验,交流、共创APP破局增长的创新思路和玩法。

Get “数据驱动运营增长” 新思路

用户增长专家 徐梓超:

《数智时代的运营新思路》

资深互联网运营专家 韩叙:

《如何挖掘内容红利促增长》

芒果TV:

《数据驱动的用户增长策略设计与落地》

网易云音乐:

《数据驱动活跃和留存》

哈啰出行:

《自动化营销之路》

携程智行火车票:

《OTA行业的智能用户运营》

萌宝公司:

《数据驱动增长》

此外,个推也和行业伙伴展开合作,实现了产品能力上的融合升级,针对特定运营场景推出了全新解决方案,比如在用户触达场景融合了AI外呼能力,帮助APP更智能地与用户连接;结合自身在消息推送和运营增长方面的经验知识,对开源大模型进行精调,推出文案圈人模型和AI文案生成等新功能,帮助APP提升用户触达和运营效率。

继续阅读 »


在较早迈入数字化进程的互联网行业,企业已经积累了大量的数据资源。如何将数据资源转化成数据资产,用数据驱动运营策略优化、产品体验升级和业务增长,是当下很多互联网企业的关注热点。

个推推出的“数智运营服务”,就是旨在帮助APP实现“让数好用,把数用好”,用数据驱动APP运营增长。它的“增长力”也在具体的实践中得到验证,已经成功帮助社交、影音等多个行业的APP客户实现运营效率和效果的双双提升。

新年新气象,APP运营也要挖掘和把握新的增长点。本文用5个关键词,带大家解锁个推数智运营服务的强劲“增长力”,希望给广大APP带来创新的运营思路,在新的一年收获全新增长!

                                                                                                                关键词一  

                                                                                                              #数智融合  

这里的融合包含两个层面的含义:

其一,是指数据层面的融合。丰富的数据是企业开展数智运营的前提,很多互联网企业在通过APP给用户提供服务的同时,还构建了小程序、Web、H5等多元形态的产品矩阵,这就需要企业将APP端数据和其他渠道的数据融合起来;此外在用户画像构建、行为特征分析等场景下,企业有时还需要借助“他山之石”,融合个推等服务商的端外数据能力,构建坚实、丰富的数据底层,才能支撑复杂的分析需求。

其二,是指经验和能力的融合。个推数智运营服务本身就是个推数智能力、产品工具和运营经验的深度融合,其定位不仅仅是解决APP运营单点问题的一款工具或产品,而是作为整体解决方案,为APP进行用户生命周期管理的各个垂直场景增能,助力APP提升关键运营指标,最终实现破局增长和运营进阶。

需要强调的是,其实APP本身就有很多运营经验和能力的积累,并且这些经验和能力已经在实际的业务场景中得到测试和验证。因此个推数智运营服务也注重将自身在移动互联网运营领域的用数经验与APP自身的运营经验融合。在服务APP客户的过程中,个推的数据专家、运营专家和APP的运营负责人、增长负责人一起,聚焦具体的场景问题,共同探寻以数据为驱动的、切实有效的运营增长方案。

                                                                                                            关键词二  

                                                                                                           #链路打通  

在实现融合的基础上,个推数智运营服务还打通了APP运营的数据流和业务流,将APP整个运营链路上从用户洞察、分层到人群圈选再到用户触达等各个环节串联起来,构建以数据为驱动的运营增长闭环。


通过个推数智运营服务,APP能够一站式地完成日常运营工作,让运营工作更丝滑、更高效,从而把更多的精力放在具体的运营场景中,并快速运用数据精准量化和分析运营效果,指导运营策略的优化。

                                                                                                          关键词三  

                                                                                                          #聚焦场景  

上文提到,个推数智运营服务融合了个推这十余年来服务数十万APP过程中所积累的丰富运营经验。个推将这些经验产品化、服务化,以规则标签、算法模型、策略模板等形式,让更多的APP客户能够直接“拿来即用”,快速解决运营难题。

目前,个推已经在用户触达、新用户冷启动、沉默用户促活、付费用户预测、流失用户预测、用户卸载分析等运营场景重点发力,和行业客户一起探索如何用好数据来实现用户生命周期的延长和商业转化上的增长。

比如,在用户触达场景,个推将大数据标签能力和算法模型能力融入到消息推送服务中,让APP能够自主圈选处于不同生命周期阶段、具有差异化兴趣偏好的细分人群,实现精细化用户触达和生命周期管理;

尤其是在付费用户预测场景,个推融合APP端内数据构建付费预测模型,通过look-alike扩量,帮助APP圈选出高潜力付费人群,实现定向转化引导,从而提升APP的商业变现能力。

                                                                                                        关键词四  

                                                                                                       #增能提效  

目前个推已经和咪咕视频、苏e行、心动日常、快音、TT语音等多个行业的APP客户合作开展数智运营实践,并取得了显著成效。

比如,助力咪咕视频实现精细化用户触达和智能内容推荐,使用户活跃和留存大幅提升;输出人群画像分析能力,助力苏e行APP实现精细化用户洞察,使新用户留存率提升23%;通过付费预测模型,助力心动日常APP挖掘高潜付费用户,使会员付费转化率提升8%;输出端外数据洞察能力,助力快音APP精细化用户分层和触达,使消息推送点击率提升150%;通过文案圈人模型,助力TT语音智能匹配文案和人群,使消息推送点击率提升120%。


关键词五

                                                                                                       #行业共创  

在运营增长方面,不同行业的APP遇到的痛点、难点,既有差异化的部分,也有很多共性的部分。2023年个推以“数据驱动运营增长”为主题,聚集了多位行业内的资深运营专家,以及来自芒果TV、网易云音乐、哈啰出行、携程智行火车票、萌宝公司等知名互联网企业的APP增长官,分享运营实践经验,交流、共创APP破局增长的创新思路和玩法。

Get “数据驱动运营增长” 新思路

用户增长专家 徐梓超:

《数智时代的运营新思路》

资深互联网运营专家 韩叙:

《如何挖掘内容红利促增长》

芒果TV:

《数据驱动的用户增长策略设计与落地》

网易云音乐:

《数据驱动活跃和留存》

哈啰出行:

《自动化营销之路》

携程智行火车票:

《OTA行业的智能用户运营》

萌宝公司:

《数据驱动增长》

此外,个推也和行业伙伴展开合作,实现了产品能力上的融合升级,针对特定运营场景推出了全新解决方案,比如在用户触达场景融合了AI外呼能力,帮助APP更智能地与用户连接;结合自身在消息推送和运营增长方面的经验知识,对开源大模型进行精调,推出文案圈人模型和AI文案生成等新功能,帮助APP提升用户触达和运营效率。

收起阅读 »

页面使用rpx布局并未适配

页面的margin-top使用了rpx并未适配所有机型

页面的margin-top使用了rpx并未适配所有机型

hbuilderX进行ios的云打包,hbuilderX控制台报错

iOS打包

错误内容:时间: 2024-01-17 15:22:20 类型: iOS Appstore 打包失败 错误日志: https://ide.dcloud.net.cn/build/errorLog/265d2670-b509-11ee-9b7b-b3a8c204e05c
1:打开错误日志,搜索error字段,如果出现了附件中圈起来的相同字段,说明我们遇到的问题是相同的
2:出现问题的原因:ios的应用图标配置不符合苹果官方要求
3:解决方法:在manifest.json—>APP图标配置——>在自动生成图标的地方重新上传图标

继续阅读 »

错误内容:时间: 2024-01-17 15:22:20 类型: iOS Appstore 打包失败 错误日志: https://ide.dcloud.net.cn/build/errorLog/265d2670-b509-11ee-9b7b-b3a8c204e05c
1:打开错误日志,搜索error字段,如果出现了附件中圈起来的相同字段,说明我们遇到的问题是相同的
2:出现问题的原因:ios的应用图标配置不符合苹果官方要求
3:解决方法:在manifest.json—>APP图标配置——>在自动生成图标的地方重新上传图标

收起阅读 »

【重要!】uni一键登录SDK升级公告 - 立即行动

一键登录

尊敬的DCloud用户,您好!
根据联通运营商的通知,联通运营商内部对一键认证产品SDK进行重构和统一管理。全新版本的SDK与原版本不兼容,因此

旧版联通一键认证SDK将于 2024年5月31日停止服务。届时,在联通网络下将无法正常使用一键登录功能。

注意:
云端打包:如果您已经使用HBuilderX3.99及以上版本重新打包并发布了一键登录的App,请忽略此公告。
离线打包:请更新Android、IOS离线SDK至最新版本

继续阅读 »

尊敬的DCloud用户,您好!
根据联通运营商的通知,联通运营商内部对一键认证产品SDK进行重构和统一管理。全新版本的SDK与原版本不兼容,因此

旧版联通一键认证SDK将于 2024年5月31日停止服务。届时,在联通网络下将无法正常使用一键登录功能。

注意:
云端打包:如果您已经使用HBuilderX3.99及以上版本重新打包并发布了一键登录的App,请忽略此公告。
离线打包:请更新Android、IOS离线SDK至最新版本

收起阅读 »

年底接活,接前端项目,免费UI;(目前担任前端负责人)-有意可以私聊,价格友好可谈,手下好几个人伙伴,产出速度快,质量有把控。

合作联系:
==========
WX:isDesignPro
邮箱:1028993962@qq.com
==========

备注:Uniapp

合作联系:
==========
WX:isDesignPro
邮箱:1028993962@qq.com
==========

备注:Uniapp

在base64转本地文件(如pdf,apk,音频等)如果base64长度过长 在 安卓中 Base64.decode(str, 0) 返回 null 的解决问题

base64

在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转文件至本地的经验了,避免下一个人踩坑。

继续阅读 »

在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转文件至本地的经验了,避免下一个人踩坑。

收起阅读 »

备案公钥MD5值获取

备案 app备案

9月后,现在上架的app都需要备案了,网上的教程不是要用命令行就是要用程序去获取,都太麻烦了。

分享一个视化工具,上传证书就可以获取app的公钥和MD5值,省去了很多时间:

推荐个,备案签名在线获取:https://beian.huai2345.com/

9月后,现在上架的app都需要备案了,网上的教程不是要用命令行就是要用程序去获取,都太麻烦了。

分享一个视化工具,上传证书就可以获取app的公钥和MD5值,省去了很多时间:

推荐个,备案签名在线获取:https://beian.huai2345.com/

一键登录应用转让

一键登录

在一些场景下:

  1. 开发者离职,需要由其他开发者接手;
  2. 开发者参加其它项目,当前项目需要由其他开发者继续维护;
  3. 外包项目结项后,应用资产需要进行转移;
  4. 其它适用场景

这时可以使用应用转让功能,将应用所有权转让给新的开发者。

发起转让前注意事项:
一键登录账户将不再提供API密钥,也就是说云函数里不需要填写apikey、apisecret

但是要保证服务空间跟一键登录都在同一个账户下,所以转让前确认新账号是否购买了服务空间

比如:应用转让到B账户下 那么一键登录云函数也要部署到B账户的服务空间下,否则获取手机号接口会调用失败 提示“应用所有者账号信息异常,请检查账号uni一键登录服务是否正常”

如何操作应用转让?
参考

应用转让成功后 在HX里切换新账号 找到一键登录项目 绑定新服务空间 重新发布云函数

应用转让成功后 旧账号一键登录余额怎么办?
可以发邮件到service@dcloud.io邮箱 说明原因 申请退款

继续阅读 »

在一些场景下:

  1. 开发者离职,需要由其他开发者接手;
  2. 开发者参加其它项目,当前项目需要由其他开发者继续维护;
  3. 外包项目结项后,应用资产需要进行转移;
  4. 其它适用场景

这时可以使用应用转让功能,将应用所有权转让给新的开发者。

发起转让前注意事项:
一键登录账户将不再提供API密钥,也就是说云函数里不需要填写apikey、apisecret

但是要保证服务空间跟一键登录都在同一个账户下,所以转让前确认新账号是否购买了服务空间

比如:应用转让到B账户下 那么一键登录云函数也要部署到B账户的服务空间下,否则获取手机号接口会调用失败 提示“应用所有者账号信息异常,请检查账号uni一键登录服务是否正常”

如何操作应用转让?
参考

应用转让成功后 在HX里切换新账号 找到一键登录项目 绑定新服务空间 重新发布云函数

应用转让成功后 旧账号一键登录余额怎么办?
可以发邮件到service@dcloud.io邮箱 说明原因 申请退款

收起阅读 »

支付的云开发是否封装了requestVirtualPayment,微信的虚拟支付?

微信支付

支付的云开发是否封装了requestVirtualPayment,微信的虚拟支付?

如果没有什么时候加上啊,急需

支付的云开发是否封装了requestVirtualPayment,微信的虚拟支付?

如果没有什么时候加上啊,急需