- 使用web-view 内嵌H5 打开 实时摄像头 web-view 会自动刷新 重载 为什么?
IOS版本:17及以上 h5页面使用了原生的 摄像头接口:navigator.mediaDevices.getUserMedia。 在小程序web-view 接入h5,一旦打开h5的摄像头,web-view 就会重载。 h5页面里面含有摄像头、three.js3D模型、cocos3D模型+导航; 有时候不打开摄像头 单纯的跳转页面返回web-view 也会自动刷新。 以前没升级都是好的。升级了后,就有问题了。 和 WebGPU 有没有什么关系,和内存有没有关系,求教
2023-11-13 - 使用WXWebAssembly优化运算性能
[视频] 你好,我是李艺。 上节课我们主要学习了代码的分布异步化以及插件代码的分布异步化。这节课我们学习如何使用WebAssembly技巧以及如何优化代码的执行性能。 首先我们看一个问题,WebAssembly号称是Web的汇编,它允许开发者使用Go C C++等后端强类型语言编写代码,然后将其编译为一种类似于汇编代码的二进制中间代码,使用这种代码可以在Web页面里边直接运行,汇编语言的性能是毋庸置疑的,这项技术从根本上一举弥补了解析型语言JS在执行性能上的一个不足,小程序已经添加了WXWebAssembly功能,实现了对WebAssembly技术的一个全面基础的支持,接下来我们看项目实践。 首先看实践一,使用Go语言编译WebAssembly的文件。 首先第一步我们需要编写Go语言的逻辑代码,在我们源码里面有一个叫做main.go这样的一个文件,这个文件它的一个主要作用是代替我们原来的stopwatch组件里面内嵌函数,叫做convertTimeStampToString这个函数的功能,Go语言在这个时间操作上,它有标准库方法支持,比较完善,已经不需要像JS代码那样进行时间字符串的一个拼接了,第二步编译和压缩wasm文件,编译以及压缩文件的脚本在我们最终源码里面已经写好了,这个编译脚本是build.sh,压缩脚本是compress.sh 直接取用就可以了,第三步我们要从Go语言这个源码里面拷贝并且修改一个wasm_exec.js这样的一个文件,这是让这个wasm文件与这个JS协同工作的一个桥梁,它是一个必不可少的一个文件。 源码里面有一个叫做copyjs.sh这样的一个脚本,我们使用这个脚本就可以从Go语言源码包里面拷贝出wasm_exec.js这个文件了,这里有一个问题需要注意一下,在这个小程序里面使用的时候,wasm_exec.js这个文件的源码里面有些地方必须要修改,但是这些你已经不需要做了,因为修改之后的文件我也已经放在源码里面了,还有就是同时也需要一个text_encoder.js文件,它是这个wasm_exec.js文件执行的时候需要的一个模块,在使用的时候直接拷贝到我们小程序项目里面就可以了,这里有一个非常重要的点需要注意,如果你安装的Go语言版本不是go1.17.8这个版本的话,那么就很有可能不能用我修改过的JS文件,因为这个文件它与版本是高度绑定的,换一次版本你就要修改一次。在源码里面还有一个叫做index.html这个文件,这是一个测试文件,我们运行这个文件以后可以验证编译出来的WebAssembly的文件结果是否正常。 下面我们看实践一的代码演示。 首先我们需要在我们这个项目的根目录下创建一个新的目录,用于放我们Go语言代码,我们这个目录可以起名叫做go_stopwatch,下面的事情我们要看一下我们已经编译好的最终代码了,第一个我们要拿来取用的一定是我们的Go语言的代码,main.js 这是我们第一个要启用的代码,这个文件我们可以拷贝一下放在我们的目录下面,这个文件我们可以简单看一下 它主要的一个代码,首先这个地方是一个package的一个声明,它声明我们这个包的一个名字,这个是不可或缺的一个,再往下是import 这个是模块的一个引入,我们现在使用的都是标准库的一个模块 没有第三方的,这个地方是一个zero 一个临时对象,下面我们要使用它,因为它没有必要重复创建,所以把它作为一个模块变量放在这个地方。 这个地方有一个getFormatedMiniSeconds,这个方法是我们将一个一个ts 一个时间 一个值,一个ms 一个时间值传进来以后,用Go语言进行一个格式化,格式化成这样的一种格式,在Go语言里面我们注意一下它的格式化字符串很特别,它是拿指定的时间的字符串 然后那种格式、去作为一个格式化字符串的,就是这个地方,比如说04:05这个数字我们不可以改,它就是默认作为一个特殊的字符串进行存在的,调用方式跟我们一般的Go语言的调用方式有点不一样,因为我们这个地方,本身我们参数的接收是从JS语言里面接收的,然后它返回也是向JS语言进行返回的,我们看到这个地方接收,首先this对象,第一个this对象,它的值是js.Value,而js.Value类型其实是在syscall/js标准库里面,它是这样引用出来的。 本身这个功能就是Go语言支持的这种WebAssembly文件编译的这种功能,也是官方的标准库支持的,并没有第三方的类库的参与,再往下面是args这是我们从JS传递过来的一个参数,它是一个数组,我们在这个地方取到了它的参数,第一个是ms,也就是一个毫秒的字符串,第二个是我们的一个回调函数,然后在这个地方我们是先计算,计算完成以后把计算出来这个结果传给callback,也就是JS里面的一个回调函数,传给它。 这个地方我们还用了协程,这个是Go语言里面协程的一个写法就是go func,然后后面跟一个函数然后就可以执行了,它就新开一个这样的一个协程并执行,这是Go语言里面的一个主函数 就是main,在这个里面我们首先是创建了一个channel 一个通道,这是一个需要从JS里面去获取它的console的这样的一个接口,因为我们要用它里面console.log这样一个方法,第二步我们获取了 不是获取 这是设置,我们这是Set,Get是获取,Set了一个方法,就是getFormatedMiniSeconds,这个方法稍后我们在JS里面会调用。 最后一步这个地方我们有一个阻塞这个程序退出的通道,就是有这样的一个通道读写,尝试从里面去读,但其实它里面没有东西 是读不出来的,所以它这个程序会一直停在这个地方,这是防止我们程序退出,如果你退出的话,在JS里面你就调不到这个里面设置的方法了,这就是我们Go语言的一个代码,它作为一个示例十分简单,但是它已经演示了我们如何去使用Go语言去编写一个WebAssembly这样的一个文件。 接下来我们还需要做一些工作,首先是我们要将这几个脚本文件给它拿过来,build.sh这些脚本文件一共是三个,把它给拷贝一下然后放过来,为了节省时间 所以我们脚本其实不用去手敲代码了,当然你们自己如果想练习的话也可以手敲代码。首先是build 这个代码是这样的,你在执行的时候第一步一定要先安装Go语言的语言包,并且这个版本要和我保持一致,不保持一致的后果前面我们也提到了对吧,它可能会遇到一些未知的问题,你可能有一些额外的工作需要做,这个是比较麻烦的,因为我之前已经做过了,这个脚本出来以后,接下来我们要做一个事情就是调用了,调用之前首先我们要把环境变量给它关一下,这个是它的模块的一个开关,先给它关上,关上以后我们就可以调用我们build.sh了。 脚本大概的意思它会编译我们main.go这个文件,然后编译成一个stopwatch.wasm这样的一个文件,然后执行,执行成功了,这是我们编译出来的一个文件,编译出来以后还没完,为啥还没完,因为在这个小程序里面提供了对br压缩文件这种功能的一个支持,因为这个文件它编译以后文件大小比较大,直接放到我们小程序代码包里面直接打包的话,其实会占很大的一个代码包额度,所以这个地方我们最好要进行一次压缩,压缩的话其实也很简单,我们需要使用一个叫做brotli的这样的一个模块,用这个模块对它进行压缩,这个模块如果你本地还没有的话,需要先用这个brew然后进行安装,当然如果包管理工具你没有的话,可以用上面这个指令进行先安装一下,安装以后,再安装下面的模块,安装以后然后就可以去压缩这个文件了。压缩的时候是这样,我们先把目标的位置,这是我们要放的位置,如果有的话先给它删掉,删掉以后,接下来就调它的brotli这个模块 ,然后去以我们当前的文件为基础进行压缩,废话不多说,我们就运行一下我们这个代码,已经执行完了。 我们看一下我们这个目标目录下面这个地方,在.go这个就是我们的目标文件,但是因为我们原来的它这个地方也有一个文件,所以我们可以先将它删掉,删掉以后然后再看,已经有了对吧,这是压缩 压缩以后,另外还有一个文件需要处理就是copyjs.sh,这个脚本它本质是从我们当前系统里面安装源,就是Go语言的源码里面去它的指定位置去拷贝这样的一个文件,然后拷贝到当前的目录下,当然这个脚本我现在不要去执行它,因为我本地的文件我已经做过修改了,拷贝以后如果你自己要做修改的话,我告诉你有哪些需要修改,可以拿这个IsWechat去搜索一下当前这个文件里面,你看有很多地方吗,这些地方都是要修改的,并且如果你的Go语言版本跟我这个不太一样的话,它导出来的文件也不一样,所以这就是我们前面说的,你最好与我的版本保持一致,如果是一致的话 这个文件你没必要修改了,直接拿我这个文件用就可以了。 这个地方我们还有一个web脚本,这个脚本是它原生的一个脚本,用于这个地方,我们把这个IsWechat改成false了,这个文件我们可以用在我们的另外一个测试文件里面,就是index.html,加载JS脚本,然后在下面我们这个地方有一个JS代码去加载我们这个文件对吧,编译好的这个wasm这个文件加载以后,又在这个地方去调用了这个里面的方法getFormatedMiniSeconds,这个方法就是刚才我们在Go语言里边去输出的方法、导出的方法,所有的这些文件现在这个 还有这个JS 这个 这个,这几个文件我们一起来拷贝一下,放在我们的这个地方,放进来了,然后在我们目录下面为了测试我们工程链的一个可行性,稍微可以对我们这个代码做一点点的一个修改,做一点点的修改,怎么修改,比方说我们这个地方有一个res,res是个变量,假如我们把它改一下的话,res等于,算了我们不改这个了,如果我们要用什么的话,可能还需要去添加新的模块,所以我们就拼接就可以了 我们随便给它加个后缀 加个st就好了,或者加个ms。 加完以后,第一步我们要先编译我们这个代码,build先编译,编译以后然后进行一个压缩,压缩完成以后,其实这个地方是可以通过看它的时间来判断它是不是我们修改过后的一个文件,比方说我们在这个目录,这是我们的目标目录,在资源管理器里面打开,然后你看一下它这个时间7:52对不对,这就是我们刚才发生的时间,它已经被修改了,接下来我们测试 怎么测试,首先我们要看一下这个文件正不正常,这个地方有一个专门用于测试的文件,这个文件我们可以拿一个插件Live Server,Live Server是我安装的,你可以在VSCode里面进行安装,我们在浏览器里面打开这个文件,然后打开调试区看一下这个地方 看到没有,get res 然后后面有一个时间字符串,并且后面多了一个ms,因为ms是我们刚才新加的对吧,调用结果说明我们这个测试的代码是没有问题的。 接下来我们开始搞 再往下检查一下我们这些文件,在这个目录下br文件已经有了对吧,text_encoder文件也有了,然后wasm_exec.js这个文件有了,并且这个里面我们可以看到它前面IsWechat等于true,正是我们要在小程序里面使用的这个版本,代码演示我们就说到这里。 接下来我们看实践二,在小程序里面创建和使用stopwatch_go组件。 第一步首先我们需要将相关的这个JS文件,wasm文件等这些文件全部拷贝到我们目录下面,与我们组件放在一起,并且在这个目录下面要依照原来的stopwatch组件的代码创建新的组件,stopwatch_go组件的JS代码就是在我们原来组件的基础之上然后修改过来的,在这个组件里面有一个特殊的flag变量,这个变量的作用是节制我们对WebAssembly文件的调用,为什么要节制呢,因为跨程序文件之间的调用,它与这个设备性能有很大的关系,我们并不能保证调用之后多久可以拿到返回的结果,所以这个地方我们一定要有节制,stopwatch_go组件的wxss样式代码还有它的wxml这个标签代码与我们原来组件是一样的 没有变化,直接拷贝过来就可以使用了,第二步就是我们要修改主页配置里面对组件的一个使用,开始使用新组件然后进行测试,从最终的一个测试结果来看效果还是不错的,下面我们开始代码演示。 下面我们开始实践二的代码演示。 目前在我们这个项目里面的wasm.br组件已经准备好了 我们看一下,在这个目录下 这个文件就是我们新编译的一个文件 对吧,这个组件代码已经有了,当它是从我们最终源码里面拷贝过来就可以了,简单看一下wxml标签代码跟之前是一样的,样式代码也没有变化,然后在JS文件里面 这个文件里面我们要看一下,重点是在这里面,这个地方我们引入了一个wasm_exec.js这个文件,这个文件就是先前我们拷贝过来的对吧,放在这个组件目录下的,然后第二个是我们做了一个路径,就是这个文件的一个路径,wasm.br这个文件的一个路径,这个路径不能使用相对地址,必须使用绝对地址,再往下,上面这些都是一样的,然后在我们的methods里面有一个intGo初始化,因为在使用之前我们要初始化,初始化我们在哪里调用 在lifetimes是我们组件的生命周期,它的这样一个函数组,其中里面有个ready是周期函数,在这个ready里面是组件准备好以后我们要执行代码,这个地方我们看global.console等于console,这个里面是去命名我们Go语言里面设的打印的代码接口,设置接口以便Go语言可以调用。 这个地方我们用了await,然后去等待我们的初始化代码的一个完成,因为它如果初始化不完成的话,你调用它是没有作用的,必须等它初始完成,而且这个初始化它不是很快就可以完成,这个地方是访问从global.Go上面,这个是全局的对象,从上面然后去访问它再调用WXWebAssembly,instantiate这个是小程序它本身提供的接口方法去实例化这个文件,实例化以后,其实这个代码它执行到这个位置,可以认为它第一次执行已经结束了,然后其实它不会有一个结果,它如果要有结果的话就是我们Go语言main那个方法它退出了,如果它退出的话接下来你去调用JS 调用Go里面那个方法就调用不到了,所以这个地方初始化其实它只是执行了一次,执行了第一次那个方法,后面那个是走不到的。 再往下就是start stop还有switch,stop和switch没有什么变化 和原来是一样的,重点是start里面 在这个里面我们有变化,这个地方,这个名字还是原来的名字,这个地方我们去直接在global上面调了getFormatedMiniSeconds,这个方法其实是Go语言通过WebAssembly,通过那个文件然后写到全局对象上的,所以我们在这个地方可以调用,把ts传给它,然后拿到这个res 就是我们那个结果,再通过setData然后进行视图的一个渲染。 这个地方注意有一个flag,我们刚才提到了我们要加一个flag,为什么加一个flag 就是为了标识一下每次调用成功以后,我们才可以进行第二次的一个调用,如果是上一次调用没有回来 你这次不要去急着去调用,如果你调用多的话,CPU 内存可能就吃不消了,程序可能就卡死了,所以这个地方我们看到这有一个flag,它每次有一个循环就是一个定时器,然后去调用,这样的一个结果,这就是这个代码。 接下来我们开始修改我们调用代码,开始去使用我们写的组件,在我们index文件里面看一下这个地方把这个组件的地址改成_go 对不对,只要改这一个地方就可以了,其他地方其实不需要修改,然后编译,有的时候组件它是不显示的,但是我们需要有一点点的耐心,可以清一下编译缓存然后重新再点一下编译按钮,是这样的,刚才我把index_addons分包给它删掉了,因为之前测试它老是加载不到这个组件,所以我们把分包给它去掉,分包去掉以后组件,我们index_addons这个目录其实现在已经属于主包了,所以我们现在把它去掉以后,它其实可以更优先被加载,优先被注入和使用。 现在这个文件,这个组件已经显示了,然后我们尝试去单击这个组件,看到没有,有变化,后面这有一个ms,原本那个文件里面是没有了ms是我们刚才新加的,而且看起来好像很流畅,具体流不流畅,其实无法靠我们的视觉进行评判,因为视觉会产生误差,特别是同样的一个代码,如果你在你自己的机器上运行和你同事的机器上运行,可能它这个结果,产生性能的表现它也是不一样的,比较公平的一个方式就是我们查看Performance面板,让它启动,然后打开Performance面板的一个录制按钮,等到执行几次以后单击停止,这一段已经停止了所以它后面没有,然后这一段是执行时间,我们可以看到这个性能是相当的喜人,总执行时间只有7ms 7毫秒,看见没有,厉害,Go语言果然很强大,这个地方18毫秒,所以它这么短的时间根本就没有红三角,这个时间其实是反应是很快的,从直观上来看,单击以后你看这个很流畅,然后再单击停止也很流畅,所以这个效果还是很不错的。 当然这个跟我们做了一些优化也有关系,因为我们前面提到了,这个文件里面我们加了一个flag,如果你没有这个flag的话,你认着这个定时器,然后一直往Go语言的那个wasm文件里面去发请求的话,它如果处理不过来,你积压这个请求越来越多,最后你这个内存它会一直飙升,然后拖到最后可能就把你这个程序给拖垮,所以在合适的节奏里面去调用这个代码是相当重要的。我们代码演示就说到这里。 最后我们来总结一下,Go语言是强类型编译语言,它被称作是互联网时代的C语言,根据2022年3月份腾讯发布的研发报告,Go语言在腾讯内部项目里面的使用已经超过了C++,成为腾讯后台编程语言里面的第一选择。我们在Go语言里边还使用了协程,还有就是我们这个代码实例其实逻辑也十分简单,所以我们一点也不怀疑我们Go语言代码的执行效率,那么在这种情况下,为什么还要在这个小程序里面,在调用这个wasm这个文件的时候还要加上这个调用限制,Go语言它执行效率虽然很高,但是JS和Go语言之间相互调用中间还有一个wasm_exec.js这个文件,这个文件它是无法跨过的一个瓶颈,所以WebAssembly这种技术适合做大块数据的一个运算,运行一次相比JS执行可以节省很多时间,但其实它并不适合高频运算这样的一个需求场景。这节课我们就讲到这里,现在屏幕上显示的网址是我们本节课所涉及的文档地址。 点击查看开放文档: 性能与体验 /WXWebAssembly 这节课我们主要学习到如何使用Go语言编写代码、如何编译为这个wasm文件以及如何在这个小程序里面使用WebAssembly的技术。下节课我们学习异步转同步的编程范式。 最后我们看一下思考题,这里有一个问题请你思考一下,就是异步编程它是JS的一大特点,但是太多的回调函数一层嵌套一层又使得这个代码看起来逻辑非常的不清晰,非常不利于维护,那么有没有一种办法既可以享有异步编程的无阻塞优点,又能保持我们这个代码的清晰连贯性,这个问题先留给你思考一下。下节课我们一起来深入探讨一下这个问题。
2022-07-14 - 微信小程序WXWebAssembly导入wasm文件报错?
微信小程序WXWebAssembly导入wasm文件报错? 我看到官方其实对webassembly是支持的,具体的官方文档如下所示 https://developers.weixin.qq.com/miniprogram/dev/framework/performance/wasm.html 是这样的,我们有个小程序产品里面有很多的音频文件,为防止这个音频文件被抓取,我们对音频文件做了一次加密,现在要在小程序完成解码并播放的功能 目前在PC端和H5端的产品体系都已经完成了,在小程序对接的时候遇到WXWebAssembly导入报错的问题,具体报错的日志如下所示 初始化失败 TypeError: WebAssembly.instantiate(): Impor #0 module="env" error: module is not an object or function [图片] 代码片段如下 https://developers.weixin.qq.com/s/dN26u5mb7yIg 备注, 对应的wasm文件也在该代码片段中,同时,我写了一个helloworld的示例代码,引入也是报错的。 由于我们的产品的用户对微信小程序非常依赖,还希望能尽快在小程序端上线,谢谢大家。
2023-05-09 - 网页授权域名数量限制?
网页授权域名目前只能设置两个,能否再增加一个?
2022-03-03 - 求助:小程序如何使用FormData传二进制文件(binary)?
**背景:在飞书小程序开发(和微信小程序类似),需要获取到文本的图片信息,请求飞书接口返回的图片信息是一个二进制流,获取获取blob一个对象。需要把这个图片数据上传到公司的服务器上,变成自己公司的图片。 **公司的接口数据 --需要的数据效果在Google控制台效果是这样的 [图片] --请求头有用boundary包裹 [图片] --这个接口是原来存在的,在vue项目里可以跑通,现在我在小程序里面调用这个接口数据就传不过去。 **我获取到的数据形式 --在小程序里我能获取到图片的二进制流数据或者blob对象,如下 [图片] 或这种格式 [图片]
2022-02-21 - 公众号跳转H5页面,IOS可以正常跳转,Android显示无法打开网页
请开发者先自查出现404异常的资源响应头部,检查content-length是否小于2048, 如果小于2048,建议在出现404异常的html 末尾增加一个隐藏的 div标签,display设置为none: <div> this is padding data: xxxx 填充整个页面content-length到2048字节以上即可 </div> 以上是暂时的解决策略,我们会在后续的版本解决。
2019-11-26 - 小程序webview组件,小程序和webview交互,小程序内联h5页面,小程序webview内网页实现微信支付
小程序支持webview以后,我们开发的好多h5页面,就可以直接在小程序里使用了,比如我们开发的微信商城,文章详情页,商品详情页,就可以开发一套,多处使用了。我们今天来讲一讲。在小程序的webview里实现微信支付功能。因为微信不允许在小程序的webview里直接调起微信支付。所以我们这节课就要涉及到小程序和webview的交互了。 老规矩先看效果。 因为这里涉及的东西比较多,录gif太多,没法上传,我就录制了一段视频出来。 https://v.qq.com/x/page/t0913iprnay.html 原理 先说下实现原理吧,实现原理就是我们在webview的h5页面里实现下单功能,然后点击支付按钮,我们点击支付按钮的时候会跳转到小程序页面,把订单号,订单总金额,传递到小程序里,然后小程序里使用订单号和订单金额去调起微信支付,实现付款,付款成功或者失败时都会有回调。我们再把对应的回调传递给webview,刷新webview里的订单和支付状态。 一,定义webview显示h5页面 关于webview的使用,我就不做讲解了,官方文档里写的很清楚,用起来也很简单。https://developers.weixin.qq.com/miniprogram/dev/component/web-view.html [图片] webview很简单,就是用一个webview组件,显示我们的网页。 二,定义h5页面 我这里启动一个本地服务器,用来展示一个简单的h5页面。 [图片] 上图是我在浏览器里显示的效果。 接下来我们在小程序的webview里显示这个页面,也很简单,只需要把我们的src定义为我们的本地网页链接就可以了。 [图片] 这里有一点需要注意 因为我们是本地链接,我们需要到开发者工具里把这一项给勾选。 [图片] 三,来看下h5页面代码 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>小程序内嵌webview</title> <style> .btn { font-size: 70px; color: red; } </style> </head> <body> <h1>我是webview里的h5页面</h1> <a id="desc" class="btn" onclick="jumpPay()">点击支付</a> <script type="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.3.2.js"></script> <script> console.log(location.href); let payOk = getQueryVariable("payOk"); console.log("payOk", payOk) if(payOk){//支付成功 document.getElementById('desc').innerText="支持成功" document.getElementById('desc').style.color="green" }else{ document.getElementById('desc').innerText="点击支付" } //获取url里携带的参数 function getQueryVariable(variable) { var query = window.location.search.substring(1); var vars = query.split("&"); for (var i = 0; i < vars.length; i++) { var pair = vars[i].split("="); if (pair[0] == variable) { return pair[1]; } } return (false); } function jumpPay() { let orderId = Date.now();//这里用当前时间戳做订单号(后面使用你自己真实的订单号) let money = 1;//订单总金额(单位分) let payData = {orderId: orderId, money: money}; let payDataStr = JSON.stringify(payData);//因为要吧参数传递给小程序,所以这里需要转为字符串 const url = `../wePay/wePay?payDataStr=${payDataStr}`; wx.miniProgram.navigateTo({ url: url }); // console.log("点击了去支付", url) console.log("点击了去支付") } </script> </body> </html> [代码] h5代码这里不做具体讲解,只简单说下。我们就是在点击支付按钮时,用当前时间戳做为订单号(因为订单号要保证唯一),然后传一个订单金额(单位分),这里节约起见,就传1分钱吧,花的是自己的钱,心疼。。。。 关键点说一下 1, 必须引入jweixin,才可以实现h5跳转小程序。 <script type=“text/javascript” src=“https://res.wx.qq.com/open/js/jweixin-1.3.2.js”></script> 2,跳转到小程序页面的方法 [代码]const url = `../wePay/wePay?payDataStr=${payDataStr}`; wx.miniProgram.navigateTo({ url: url }); [代码] 这里要和你小程序的页面保持一致。payDataStr是我们携带的参数 [图片] 四,小程序支付页 来看下我们的小程序支付页 [图片] 小程序支付页功能很简单,就是来接收我们h5传过订单号和订单金额。然后去调起微信支付,实现支付。支付成功和支付失败都有对应的回调。 [图片] 支付我们这里实用的小程序云开发来实现的支付,核心代码只有10行。由于支付不是本节的重点,所以这里不做具体讲解。感兴趣的同学可以去看我写的文章和我录的视频 小程序支付文章:https://www.jianshu.com/p/2b391df055a9 小程序支付视频:https://edu.csdn.net/course/play/25701/310742 下面把小程序接收参数和支付的完整代码贴出来给大家 [代码]Page({ //h5传过来的参数 onLoad: function(options) { console.log("webview传过来的参数", options) //字符串转对象 let payData = JSON.parse(options.payDataStr) console.log("orderId", payData.orderId) let that = this; wx.cloud.callFunction({ name: "pay", data: { orderId: payData.orderId, money: payData.money }, success(res) { console.log("获取成功", res) that.goPay(res.result); }, fail(err) { console.log("获取失败", err) } }) }, //微信支付 goPay(payData) { wx.requestPayment({ timeStamp: payData.timeStamp, nonceStr: payData.nonceStr, package: payData.package, signType: 'MD5', paySign: payData.paySign, success(res) { console.log("支付成功", res) //你可以在这里支付成功以后,再跳会webview页,并把支付成功状态传回去 wx.navigateTo({ url: '../webview/webview?payOk=true', }) }, fail(res) { console.log("支付失败", res) } }) } }) [代码] 代码里注释很清楚,这里有一点,就是我们支付成功后,需要告诉h5我们支付成功了,通知h5去刷新订单或者支付状态。 到这里我们就完整的实现了小程序webview展示h5页面,并且做到了h5和小程序的交互,实现了小程序webview的支付功能。 是不是很简单呢。 源码地址 1,关注“编程小石头”公号,回复“webview”即可获取源码 2,也可以到我github下载源码 https://github.com/qiushi123/xiaochengxu_demos [图片]
2019-08-15 - 微信升级后,xweb内核下如何进行网页调试呢?
根据目前了解到的情况,微信从8.0.19开始内核从x5换成了xweb,原来使用的vConsole无法使用了,目前仅能使用Chrome浏览器调试,但是速度很慢,影响使用,官方能给回复不,什么时候能把vConsole集成进来,不然只能选择降级,不用新版本了
2022-03-17 - 小程序app.onLaunch与page.onLoad异步问题的最佳实践
场景: 在小程序中大家应该都有这样的场景,在onLaunch里用wx.login静默登录拿到code,再用code去发送请求获取token、用户信息等,整个过程都是异步的,然后我们在业务页面里onLoad去用的时候异步请求还没回来,导致没拿到想要的数据,以往要么监听是否拿到,要么自己封装一套回调,总之都挺麻烦,每个页面都要写一堆无关当前页面的逻辑。 直接上终极解决方案,公司内部已接入两年很稳定: 1.可完美解决异步问题 2.不污染原生生命周期,与onLoad等钩子共存 3.使用方便 4.可灵活定制异步钩子 5.采用监听模式实现,接入无需修改以前相关逻辑 6.支持各种小程序和vue架构 。。。 //为了简洁明了的展示使用场景,以下有部分是伪代码,请勿直接粘贴使用,具体使用代码看Github文档 //app.js //globalData提出来声明 let globalData = { // 是否已拿到token token: '', // 用户信息 userInfo: { userId: '', head: '' } } //注册自定义钩子 import CustomHook from 'spa-custom-hooks'; CustomHook.install({ 'Login':{ name:'Login', watchKey: 'token', onUpdate(token){ //有token则触发此钩子 return !!token; } }, 'User':{ name:'User', watchKey: 'userInfo', onUpdate(user){ //获取到userinfo里的userId则触发此钩子 return !!user.userId; } } }, globalData) // 正常走初始化逻辑 App({ globalData, onLaunch() { //发起异步登录拿token login((token)=>{ this.globalData.token = token //使用token拿用户信息 getUser((user)=>{ this.globalData.user = user }) }) } }) //关键点来了 //Page.js,业务页面使用 Page({ onLoadLogin() { //拿到token啦,可以使用token发起请求了 const token = getApp().globalData.token }, onLoadUser() { //拿到用户信息啦 const userInfo = getApp().globalData.userInfo }, onReadyUser() { //页面初次渲染完毕 && 拿到用户信息,可以把头像渲染在canvas上面啦 const userInfo = getApp().globalData.userInfo // 获取canvas上下文 const ctx = getCanvasContext2d() ctx.drawImage(userInfo.head,0,0,100,100) }, onShowUser() { //页面每次显示 && 拿到用户信息,我要在页面每次显示的时候根据userInfo走不同的逻辑 const userInfo = getApp().globalData.userInfo switch(userInfo.sex){ case 0: // 走女生逻辑 break case 1: // 走男生逻辑 break } } }) 具体文档和Demo见↓ Github:https://github.com/1977474741/spa-custom-hooks 祝大家用的愉快,记得star哦
2023-04-23 - 小程序内webview页面OAuth2授权问题?
小程序中,webview嵌入的网页进行OAuth2授权页面空白,授权失败。 [图片] 在微信小程序开发工具内是正常授权的: [图片] webview链接的网页直接微信浏览器打开也是正常的。 附上代码片段: [图片] h5页面中OAuth2授权的链接: [图片]
2020-11-23 - [填坑手册]小程序PC版来了,如何做PC端的兼容?!
[图片] 微信宣布小程序将可以在PC端微信打开后,智库君就接到要求,需要兼容PC端小程序,一开始以为官方已经做了完美适配,不需要改什么,但当本人下载内测版开始测试的时候,才发现或许坑还挺多的~~~ 下面分享下本人“搬砖填坑”的全过程: (以下都是PC端小程序特有的问题,手机端正常) 先说下使用流程 [图片] 微信开发者工具菜单栏点击 设置->通用设置,在自动预览部分勾选“启动 PC 端自动预览”。 使用自动预览功能,点击 预览->自动预览->编译并预览,成功的话将在微信 PC 版上自动拉起小程序。 [图片] PC版打开后就横屏问题 [图片] [代码]{ "pages": [], "resizable":false, //在这里设置false,使得小程序默认手机尺寸 "pageOrientation":"portrait", //这里默认设置即可 ... } [代码] PC版微信默认打开小程序是ipad版,这样就会出现各种形变,布局错乱,这个可以在app.json进行配置,静止自动旋转,默认手机竖屏样子打开。 页面找不到问题 [图片] 这个问题本人也找了很久,一直很纳闷IDE工具和手机打开看都没什么问题,用PC打开小程序就出现页面找不到的情况,大致报错是: [代码]page[pages/XXX/XXX] not found.May be caused by :1. Forgot to add page route in app.json.2. Invoking Page() in async task. [代码] 一般这种情况以往是 app.json没配,或者页面里面缺少page(),但这次诡异的地方是只有“PC版小程序”报这个错!后来分析问题发现是:目前PC版小程序不能直接支持ES6,必须转换成ES5,同时由于一些语法转化不够完善,特别是ES7中的await 和 async 导致转化二次报错,这里就需要打开 “增强编译” 配置。 [图片] 打开有CSS报错 [图片] 因为目前PC版小程序估计内核的机制问题,还只支持低版本的选择器,如果你直接写小程序的标签,它无法识别,比如 [代码].popCont navigator{ //navigator 标签是小程序里的,PC端无法支持 width: 560rpx; height: 300rpx; } .popCont image{ //image 标签是小程序里的,PC端无法支持 width: 560rpx; height: 300rpx; } [代码] 但这些写法,其实在手机小程序和IDE工具里是完全正常的,PC版需要做兼容,改成class选择器。 布局结构混乱 如果遇到这种情况,会检查一下是否使用屏幕尺寸(rpx)来计算布局,PC 上屏幕尺寸比窗口尺寸大,应该使用窗口尺寸来计算。 小程序如何判断是 PC 平台? 通过 getSystemInfo 官方接口(platform 是 windows) 通过 UA(PC UA 包含 MiniProgramEnv/Windows) 微信官方PC版小程序内测地址: https://dldir1.qq.com/weixin/Windows/WeChat2.7.0_beta.exe 最新官方IDE调试工具 https://developers.weixin.qq.com/miniprogram/dev/devtools/nightly.html 往期回顾: [打怪升级]小程序评论回复和发帖功能实战(二) [打怪升级]小程序评论回复和发贴组件实战(一) [填坑手册]小程序Canvas生成海报(一) [拆弹时刻]小程序Canvas生成海报(二) [填坑手册]小程序目录结构和component组件使用心得
2021-09-13 - 小程序没有 DOM 接口,原因竟然是……?
拥有丰富的 Web 前端开发经验的工程师小赵今天刚刚来到新的部门,开始从事他之前没有接触过的微信小程序开发。在上手的第一天,他就向同办公室的小程序老手老李请教了自己的问题。 小赵:翻了一圈文档,小程序好像并不提供 DOM 接口?我还以为可以像之前一样用我喜欢的前端框架来做开发呢。老李,你说小程序为什么不给我们提供 DOM 接口呀。 老李:要提供 DOM 接口也没那么容易。你知道小程序的双线程模型吗?(小赵漏出了疑惑的表情)小程序是基于 Web 技术的,这你应该知道,但小程序和普通的移动端网页也不一样。你做了很多前端项目了,应该知道在浏览器里,UI 渲染和 JavaScript 逻辑都是在一个线程中执行的? 小赵:这我知道,在同一个线程中,UI 渲染和 JavaScript 逻辑交替执行,JavaScript 也可以通过 DOM 接口来对渲染进行控制。 老李:小程序使用的是一种两个线程并行执行的模式,叫做双线程模型。像我画的这样,两个线程合力完成小程序的渲染:一个线程专门负责渲染工作,我们一般称之为渲染层;而另外有一个线程执行我们的逻辑代码,我们一般叫做逻辑层。这两个线程同时运行,并通过微信客户端来交换数据。在小程序运行的时候,逻辑层执行我们编写的逻辑,将数据通过 setData 发送到渲染层;而渲染层解析我们的 WXML 和 WXSS,并结合数据渲染出页面。一方面,每个页面对应一个 WebView 渲染层,对于用户来说更加有页面的感觉,体验更好,而且也可以避免单个 WebView 的负担太重;另一方面,将小程序代码运行在独立的线程中的模式有更好的安全表现,允许有像 open-data 这样的组件可以在确保用户隐私的前提下让我们展示用户数据。 [图片] 小赵:怪不得所有和页面有关的改动都只能通过 setData 来完成。但是用两个线程来渲染我们平时用单线程来渲染的 Web 页面,会不会有些「浪费」?而且每一个页面有一个对应的渲染层,那页面变多的时候,岂不是会有很大的开销? 老李: 并不浪费,因为界面的渲染和后台的逻辑处理可以在同一时间运行了,这使得小程序整体的响应速度更快了。而在小程序的运行过程中,逻辑层需要常驻,但渲染层是可以回收的。实际上,当页面栈的层数比较高的时候,栈底页面的渲染层是会被慢慢回收的。 小赵: 原来如此。这么说的话,实际的 DOM 树是存在于渲染层的,逻辑层并不存在,所以逻辑层才没有任何的 DOM 接口,我明白了。但是……既然可以实现像 setData 这样的接口,为什么不能直接把 DOM 接口也代理到逻辑层呢?我觉得小程序可以做一个封装,让我们在逻辑层调用 DOM 接口,在渲染层调用接口后再把结果返回给我们呀。 老李:从理论上来说确实是可以的。但是线程之间的通信是需要时间的呀。将调用发送到渲染层,再将 DOM 调用结果发送回来,这中间由于线程通信发生的时间损耗可能会比这个接口本身需要的时间要多得多。如果以此为基础使用基于 DOM 接口的前端框架,大量的 DOM 调用可能会非常缓慢,让这个设计失去意义。 在实际测试中,如果每次 DOM 调用都进行一次线程通信,耗时大约是同等节点规模直接在渲染层调用的百倍以上;如果忽略通信需要的时间,一个实现良好的基于 DOM 代理的框架可以近似地看成一个动态模板的框架,而动态模板和静态模板相比要慢至少 50% 小赵:原来如此,线程通信的时间确实是我没有考虑到的问题。那现在的小程序框架中难道不存在这个问题吗? 老李: 在现在的小程序框架中,这个问题也是存在的,这也是现在的框架基于静态模板渲染的原因。静态模板可以在运行前就做好打包,直接注入到渲染层,省去线程传输的时间。在运行时,逻辑层只和渲染层进行最少的、必要的数据交换:也就是渲染用的数据,或者说 data 。另一方面,静态模板让两个线程都在启动时就拥有模板相关的所有数据,所以框架也充分利用了这一点,进行了很多优化。 小赵: 怪不得我在文档里发现很多和 setData 有关的性能提示,都提醒尽量减少设置不必要的数据,现在总算是知道为什么了。但是具体到实际开发里的时候,还是总觉得很难每次只设置需要的数据啊,像对象里或者数组里的数据怎么办呢? 老李: 如果只改变了对象里或者数组里的一部分数据,可以通过类似 array[2].message , a.b.c.d 这样的 数据路径 来进行「精准设置」。另外,现在自定义组件也支持 纯数据字段 了,只要在自定义组件的选项中设置好名为 pureDataPattern 的正则表达式, data 中匹配这个正则的字段将成为纯数据字段,例如,你可以用 /^_/ 来指定所有 开头的数据字段为纯数据字段。所有纯数据字段仅仅被记录在逻辑层的 this.data 中,而不会被发送到渲染层,也不参与任何界面渲染过程,节省了传输的时间,这样有助于提升页面更新性能。 小赵:小程序还有这样的功能,受教了。不过说来说去,我还是想在小程序里用我顺手的框架来开发,毕竟这样事半功倍嘛。我在网上搜索了一下,发现现在有很多支持用 Web 框架做小程序开发的框架,但好像都是将模板编译成 WXML,最终由小程序来做渲染,但这样的方法好像兼容性也不是很好。我在想,我们能不能在逻辑层仿造一套 DOM 接口,然后在运行时将 DOM 调用适配成小程序调用? 老李: 你的这个脑洞有一些意思。在逻辑层仿造一套 DOM 接口,直接维护一棵 DOM 树,这当然没问题。但是没有代理 DOM 接口,逻辑层的 DOM 树没法反映到渲染层,因为渲染层具体会出现什么样的组件,是运行时才能知道的,这不就没法生成静态模板了? 小赵:静态模板确实是没法生成了,但我看到小程序的框架支持自定义组件,我是不是可以做一个通用的自定义组件,让它根据传入的参数不同,变成不同的小程序内置组件。而且自定义组件还支持在自己的模板中引用自己,那么我只需要一个这个通用组件,然后从逻辑层用代码去控制当前组件应该渲染成什么内置组件,再根据它是否有子节点去递归引用自己进行渲染就可以了。你看这样可行吗? [图片] 老李: 这样的做法确实可行,而且微信官方已经按照这个思路推出小程序和 Web 端同构的解决方案 Kbone 了。Kbone 的原理就像你刚才说的那样,它提供一个 Webpack 插件,将项目编译成小程序项目;同时提供两个 npm 包,分别提供 DOM 接口模拟和你说的那个通用的自定义组件作为运行时依赖。要不你赶紧试试? 小赵:还有这么好的事,那我终于可以用我喜欢的框架开发小程序了!这么好的框架,为什么不直接内置到小程序的基础库里呀? 老李: 因为这样的功能完全可以用现在已有的基础库功能实现出来呀。Kbone 现在是 npm 包的形式,使得它的功能、问题修复可以随着自己的版本来发布,不需要依赖于基础库的更新和覆盖率,不是挺好的吗? 小赵: 好是好,但我担心的是代码包大小限制的问题。除了我们已经写好的业务逻辑之外,现在还得加上 Kbone,会不会装不下呀? 老李: 原来你是担心这个呀,放心,Kbone 现在已经可以在 扩展库 里一键搞定啦。扩展库是帮我们解决依赖的全新功能,只要在配置项中指定 Kbone 扩展库,就相当于引入了 Kbone 相关的最新版本的 npm 包,这样就不占用小程序的代码包体积了,快试试吧! 小赵:哇,那可太爽了,马上就搞起! 最后 如果你对 Kbone 感兴趣或者有相关问题需要咨询, 欢迎加入 Kbone 技术交流 QQ 群:926335938
2020-01-14 - 第二次canvasToTempFilePath会报fail canvas is empty的bug
第一次canvasToTempFilePath会生成图片 [图片] 第二次canvasToTempFilePath会报fail canvas is empty canvasToTempFilePath里面加上this也没用 [图片]
2019-11-14