为了用-Markdown-写微信公众号自定义了一个编辑器

身边应该有不少朋友在写公众号,不知道你们用的是什么编辑器呢? 135编辑器i排版秀米 XIUMI易点编辑器上面这些编辑器,应该是小编们用得最多的几款,它可以快速添加各种样式插件,使文章更吸引眼球,让用户看起来很爽,欲罢不能。毕竟他们最注重的是阅读量,而非内容。 我也有写文章的习惯,但我不是小编,格式上只追求简约大方即可,重点在文字上,希望内容能产生一些价值。自从用了 Markdown 标记语言后,写文章就再也没用过其他的编辑器。 什么是 Markdown?什么是 Markdown?它是目前最流行的写作标记语言,没有之一。它能够通过简单标记就能实现文档格式,让写作者专注于内容。 由于它是纯文本,所以它可以像代码一样进行版本管理,同时,它对 Web 也非常友好,方便转成 HTML,甚至直接将 Markdown 文档生成静态站点,很多免费的自建博客服务都是采用的这种方案。目前几乎所有主流的写作平台,其编辑器都支持 Markdown。 一些 Markdown 编辑器,甚至在其基础上,扩展了很多功能。例如:公式及表格的支持。前段时间,一个外国小哥的数学笔记火了,全程像敲代码一般,紧追数学老师板书,记了 1700 + 页笔记。感兴趣可以看下这篇文章: 1700页数学笔记火了!全程敲代码,速度飞快易搜索,硬核小哥教你上手LaTeX+Vim 为什么不支持 Markdown?虽然支持它的编辑器多到数不过来,可是国内最著名的内容发布平台 —— 微信公众号,它的编辑器就不支持 Markdown,可算折腾坏了一帮写作者。为什么不支持?可能有两个原因吧。 用户学习成本Markdown 语法虽然简单,但对大部分人来说,毕竟也是一门新的知识,这就增加了用户的学习使用成本。你要知道,绝大部分的人,哪怕一点点的新东西都是接受不了的,微信没把编辑器做成 Word 的样式,我觉得已经是克制了的。 支持的样式并不完整Markdown 只提供了简单的样式标签,例如:标题,引用,链接等等,而对于复杂的样式,例如文字背景色等等,它是不支持的。 而微信面对的是全体创作者,单纯使用 Markdown 编辑器定然不能满足基本需求,而兼容 Markdown 的需求优先级并不高。 所以,一直以来,微信并不支持 Markdown,但我猜测,支持 Markdown 的功能迟早还是会做的。 Markdown 写公众号的痛你不是说了 Markdown 对 Web 非常友好嘛,转成富文本样式,然后贴到微信公众号的编辑器里,就可以了呀。道理是没错,但这正是折腾人的关键所在,因为 Markdown 只定义了基础的标签,而没有样式。 于是,各家的 Markdown 编辑器导出的样式都是有差异的,并且,跟微信公众号上的默认样式也不兼容。所以,贴进去后,显示出来的样式各不相同,如果文章里再有一些非标准的 Markdown 语法,显示出来更是五花八门了。一直以来都很纠结,对于一些样式复杂的文章,几乎就不发公众号了,因为调整样式,就要耗费大量的精力。 除了样式兼容性问题,还有微信公众号对外部链接限制问题,公众号内文章只允许引用微信内部链接,不支持外部链接。文章里若添加了第三方链接,我们只能硬生生的将 链接重新再贴进去。或者通过「阅读原文」链接原文地址。 解决方案微信公众号编辑器都几乎成为一种新的行业了,文章开头的那些编辑器,都能自力更生了,说明对小编们来说,公众号编辑器问题真的是一个痛点。 而对于适配公众号样式的 Markdown 编辑器,几乎没有,之前接触过 Md2All,功能上很完整,但是它并非只针对微信公众号,所以在细节方面的处理,总是差强人意。 一直想着,应该写一款符合自己样式风格的公众号编辑器。然而,一个偶然机会,发现了它,花三小时写这个工具,只为一分钟拯救公众号排版。 在程序世界里,有句老话说「不要重复造轮子」,你费好大劲去研究怎么做,没准别人已经都出成品了,这样就造成了资源浪费。幸运的是,我的「轮子」还没有开始动手呢。 总要做点自己的贡献这款公众号编辑器基本符合我的心里预期,简单的界面,优雅的样式风格,你看到的这篇文章的样式,就是通过它生成的。 ...

April 28, 2019 · 1 min · jiezi

从入门到撞门手把手教你开发一款记录类小程序

最近开发了一款记录类的小程序“我我”,决定把这段时间里学到的知识由浅到深的总结一下,分享给大家,如有不对之处还望大佬指出。 目录小程序的申请开发者工具的使用小程序的开发统计发布进阶1. 小程序的申请小程序的申请流程可以照着官网的教程走,需要注意的是,后台的设置里,很多项目一个月只能改3/5次,开发-->开发设置-->服务器域名一个月也只能改5次,所以建议提前规划好要修改的内容,比如服务器域名,应该提前把接口地址、图片资源地址、统计打点地址等域名统一填好(审核有延迟,一般为1小时左右)。 另外,申请的账号邮箱最好不要用个人邮箱,建议专门注册一个产品用的,不然这个同事离职了的话账号处理会很蛋疼。 2. 开发者工具的使用 右上角详情里,可以把这些选项都点上,如果有使用npm模块,则把那个选项也点上。如果有域名还未申请或还未通过审核,可以把最后一个选项点上,就可以跳过白名单检查。如果有使用npm模块,还需要点击工具-->构建npm,生成一个miniprogram_npm文件。如果有用到shell命令去控制开发者工具,则需要把设置-->安全设置-->安全里的服务端口开启,至于如何用shell命令,以及用它的好处是什么,让我们放后面慢慢聊。 3. 小程序的开发3.1 小程序文件结构项目├── components // 组件├── node_modules // 项目依赖├── miniprogram_npm├── page // 页面├── images├── .gitignore├── app.json├── app.wxss├── app.js├── package.json├── project.config.json└── README.md3.2 自定义topbar的开发因为“我我”项目需要自定义topbar,所以需要解决这些问题: 获取胶囊到手机顶部的距离,使返回按钮和标题能自适应与胶囊处于同一行。 wx.getSystemInfo({ success: function(res) { that.globalData.comPostInfo = res; if (res.system.indexOf('iOS') > -1) { that.globalData.system = 'ios'; that.globalData.paddingTop = res.statusBarHeight + 6; } else { that.globalData.system = 'android'; that.globalData.paddingTop = res.statusBarHeight + 10; } }});通过wx.getSystemInfo的statusBarHeight能获取到胶囊到手机顶部的距离,再根据需要加上几像素令文字与胶囊居中。 另外,返回按钮并不是所有情况都该出现,当用户处于一级页面,或者通过二维码进入时,这时候就不该有返回按钮了(如果是通过二维码等方式进入,还应该加上一个返回首页的按钮),这里我们这样判断一下: let that = this;let tabs = ['pages/index/index', 'pages/find/find', 'pages/msg/msg', 'pages/me/me'] // “我我”里的4个一级页面let pages = getCurrentPages();for (let i = 0; i < pages.length; i++) { let page = pages[i]; if (tabs.indexOf(page.route) > -1) { break; } else { that.setData({ show: true }); }}通过getCurrentPages来获取当前页面列表进而判断是否有一级页面存在。 ...

April 26, 2019 · 3 min · jiezi

reactnativewechat安卓点击登录没有回调问题

项目中难免会用到第三方登录和分享,本项目中微信登录使用的第三方组件:# react-native-wechat 使用yarn add react-native-wechatreact-native link react-native-wechat在包名下新建wxapi文件夹,文件夹下新建文件WXEntryActivity.java package com.xxx.wxapi;import android.app.Activity;import android.os.Bundle;import com.theweflex.react.WeChatModule;public class WXEntryActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); WeChatModule.handleIntent(getIntent()); finish(); }}授权登录首先注册 WeChat.registerApp(WechatAppID)授权登录 WeChat.sendAuthRequest('snsapi_userinfo', 'ares') .then((response) => { console.log('-------------------- get wechat data is:', response) getWechatOpenId(response.code) }) .catch((error) => { let errorCode = Number(error.code); if (errorCode === -2) { dispatch(showDropdownAlert('error', '提示', '已取消授权登录')) // errorCode = -2 表示用户主动取消的情况,下同 } else { dispatch(showDropdownAlert('error', '提示', WechatAuthFailed)) // errorCode = -2 表示用户主动取消的情况,下同 } })注意问题打包使用签名文件keystore文件的签名要和微信开发平台中填写的一一致WXEntryActivity.java 中的package com.xxx.wxapi; 包名必须和微信开发平台中填写的包名一直,不然就会出现点击授权登录,回调没有反应的问题,可以解决这个问题:https://github.com/yorkie/rea...

April 25, 2019 · 1 min · jiezi

获取已发布微信小游戏和小程序源码

小游戏或者小程序和 H5 、 网页 不一样,不能直接F12 看代码,要怎么才能拿他们的代码呢 ? 那么具体怎么实现呢 ,接下来具体说一下: 首先需要知道的是小程序在手机里的文件储存那么这个位置具体在哪呢 ? 具体目录位置:/data/data/com.tencent.mm/MicroMsg/{{一串32位的16进制字符串名文件夹}}/appbrand/pkg/ 在这个目录下会有一些 xxx.wxapkg 这样后缀的文件,这些就是小程序或者小游戏的包。xxx.wxapkg 是什么呢?微信小程序源码阅读笔记1 这里有一篇详细介绍的文件 大家可以看一下。 获取小程序的 .wxapkg 包在电脑上用root过的安卓的手机模拟器 ,上安装RE文件管理器 ,然后通过管理器获取到的。 具体实现 :1 、 安装手机模拟器(这里我用的是夜神模拟器) 下载地址 :https://www.yeshen.com/cn/dow... 2 、 在模拟器上安装 微信 , qq ,RE管理器 RE管理器先下载到电脑上,然后再拖到模拟器里面就可以了。 RE管理器 下载地址 :YPSuperKey Checkedhttps://pan.baidu.com/s/1PPBx08rNutXxhlMMJbuTpQ 微信 ,qq 直接在模拟上下载。3 、 设置超级用户 安装好RE 管理器之后需要 给RE 设置超级用户这个权限。4 、 去缓存小游戏或小程序 打开微信 然后找到你想要获取代码的小游戏或小程序 打开这个小游戏或小程序,程序开始运行之后源文件就已经下载到本地了。5 、 找到源文件 将模拟器的操作页面切换到桌面 ,运行RE管理器 ,然后在管理器里面找到之前说到的那个目录:/data/data/com.tencent.mm/MicroMsg/{{一串32位的16进制字符串名文件夹}}/appbrand/pkg/ 这里这些就是我们需要的源文件包,然后再通过 访问的时间 找到刚才运行的程序是哪一个就可以了。6 、 压缩 ...

April 24, 2019 · 1 min · jiezi

PC端解析微信发送过来的emoji和在光标处插入emoji

最近公司的一个需求,需要在PC端接收并展示微信发送的消息,那么如何解析微信发送过来的表情?如何在编辑框光标出插入表情?本文将会详细的介绍如何解决这两个问题。一、PC端解析微信发送过来的emoji首先,我们知道,emoji的展示实际是图片的展示,input、textarea是没法展示图片的,所以我们用div里contenteditable=“true"属性,即可编辑。其次我们要了解,微信发送一个表情过来,后台数据库接收到的是/::-O这种特殊字符串,当然,如果是[微笑]这种字符串处理方式也一样,对照表可以参考微信默认表情代码和图片包,下载里面的图标到本地,并处理成如下格式页面展示表情,只需要遍历一下emoji数组,拼接一下图片的url即可。当要处理某个字符串里面的emoji时候,可遍历emoji数组,将后台接收的特殊字符串通过replace接口全局替换成对应的图片,反之,同样的方法将图片转化成微信可以解析成emoji的特殊字符,下面即是转换的函数 // 将特殊符号转成对应表情 config.imgUrl图片存放的url imgChangeEmoji(str) { emoji.forEach(element => { if (str && str.indexOf(element.code) > -1) { const effectCode = element.code.replace(/[.\[]{}()|^$?+]/g, ‘\$&’); // 转义字符串中的元字符 const pattern = new RegExp(effectCode, ‘g’); const imgUrl = &lt;img src='${config.imgUrl}/${element.img}'&gt;; str = str.replace(pattern, imgUrl); } }); return str; } // 将对话中的表情图片替换成特殊字符 config.imgUrl图片存放的url emojiChangeImg(str) { emoji.map(element => { if (str && str.indexOf(element.img) > -1) { const imgUrl = &lt;img src="${config.imgUrl}/${element.img}"&gt;; const pattern = new RegExp(imgUrl, ‘g’); str = str.replace(pattern, element.code); } }); return str; }需要特别注意的是,将特殊字符转成RegExp的时候,必须先用replace进行转义,即const effectCode = element.code.replace(/[.[]{}()|^$?+]/g, ‘\$&’); 手写转义是无效的。有了上面的解析函数,你只需在发送消息前执行emojiChangeImg(str)函数即可,同样的,如果想展示接收回来的消息,可以写个指令运行imgChangeEmoji(str)函数。二、光标处插入emoji在div添加keyup和click事件,如下代码(此处用的是angualr6) <div #editBox contenteditable=“true” (keyup)=“handleInputChange()” (click)=“handleClick()"></div>在handleInputChange()和handleClick()和函数里面设置最后光标对象 // 获取选定对象 const selection = getSelection(); // 设置最后光标对象 this.lastEditRange = selection.getRangeAt(0);选择emoji图片时创建一个img节点,并插入到最后光标位置,如下代码const img = new Image();img.src = ${config.imgUrl}/${emoji.img};const selection = getSelection();if (this.lastEditRange) { // 存在最后光标对象,选定对象清除所有光标并添加最后光标还原之前的状态 selection.removeAllRanges(); selection.addRange(this.lastEditRange);}// 选择第一选区const range = selection.getRangeAt(0);range.insertNode(img);range.collapse(false);即可在光标处插入img。想了解更多光标对象可参考html元素contenteditable属性如何定位光标和设置光标 ...

April 18, 2019 · 1 min · jiezi

安卓手机微信7.0.4调试小程序抓包https请求失败的问题和解决

注意:阅读本文需要一台已经root的安卓手机!说明系统:MacOS 10.13.6手机:小米6(已root)抓包工具:Charles微信版本:7.0.4现象安卓手机无法通过Charles代理抓包https请求,我前天(2019年04月16日)用的7.0.3不知道为什么能抓到,昨天手残更新到7.0.4就不行了。而iOS(iPhone5S 12.1.4)没有问题。查找相关资料,都说微信升级到版本7之后就限制了用户证书凭据。根据网上较多的推荐方案,建议把证书放在系统证书存放目录下,那这就需要Root手机了,如果没有,以下内容不适合阅读。接下来,我尝试将Charles生成的证书放在手机的系统证书中,并没有那么顺利,很失败!我慢慢来讲解一下。步骤生成Charles证书我们要生成一个可以存放在系统证书目录下的可被识别的证书。手机代理设置好了后,手机访问:<chls.pro/ssl>下载下来证书,名称是这样的charles-proxy-ssl-proxying-certificate.pem(你把这个文件搞到电脑上,假设该证书存在电脑的路径:~/charles-proxy-ssl-proxying-certificate.pem)。在你的电脑终端通过这个命令生成一个hash值:openssl x509 -subject_hash_old -in ~/charles-proxy-ssl-proxying-certificate.pem可以看到输出了类似如下P750TM:webs whidy$ openssl x509 -subject_hash_old -in ~/certificate.pem 07e87b3d—–BEGIN CERTIFICATE—–MIIFYjCCBEqgAwIBAgIGAWeQpfWHMA…….77JclxPc0UdJHi5rOf7w+LU8YZFPdMTLa/c2JjMlspt08UeQVDE=—–END CERTIFICATE—–将证书更名07e87b3d.0注意后缀!接下来你可以用任意手段将该文件拷贝至手机的/system/etc/security/cacerts/目录,如果成功则再次尝试抓包,如果失败,请继续看。超级终端操作如果不嫌麻烦的话,你完全可以在安卓手机上面的超级终端(自行下载的工具)进行以下操作,但是我没有这样,我在MacOSX中启用adb连接操作手机,如果你正有此意,请按照我的方式操作。电脑终端执行以下命令(这里不介绍brew,不理解的自行学习)brew cask install android-platform-tools装好后,数据线连上手机,测试一下adb devices没报错,且大概出现以下信息则正常:List of devices attached* daemon not running; starting now at tcp:5037* daemon started successfullyfa8a05fd device然后获取root权限,尝试将文件07e87b3d.0拷贝到/system/etc/security/cacerts/adb root获得权限后,直接执行下面命令将证书放入系统目录。push ~/07e87b3d.0 /system/etc/security/cacerts/如果成功了,请尝试抓包。如果提示失败,比如权限不足,只读啥的,反正大概错误信息如下:P750TM:/ whidy$ adb push ~/07e87b3d.0 /system/etc/security/cacerts/adb: error: failed to copy ‘/Users/whidy/07e87b3d.0’ to ‘/system/etc/security/cacerts/07e87b3d.0’: remote couldn’t create file: Read-only file system/Users/whidy/07e87b3d.0: 0 files pushed. 0.0 MB/s (1947 bytes in 0.119s)那就要继续折腾了。网上抄到的chmod 777目前是不管用的。要通过mount的相关操作来解决这个问题。装载可写的system目录查看当前system目录挂载在哪里mount,可以得到大致如下:rootfs on / type rootfs (ro,seclabel,size=2828452k,nr_inodes=707113)tmpfs on /dev type tmpfs (rw,seclabel,nosuid,relatime,size=2912600k,nr_inodes=728150,mode=755)devpts on /dev/pts type devpts (rw,seclabel,relatime,mode=600)proc on /proc type proc (rw,relatime,gid=3009,hidepid=2)sysfs on /sys type sysfs (rw,seclabel,relatime)selinuxfs on /sys/fs/selinux type selinuxfs (rw,relatime)/dev/block/dm-0 on /system type ext4 (ro,seclabel,relatime,discard,data=ordered)debugfs on /sys/kernel/debug type debugfs (rw,seclabel,relatime)none on /acct type cgroup (rw,relatime,cpuacct)none on /dev/stune type cgroup (rw,relatime,schedtune)tmpfs on /mnt type tmpfs (rw,seclabel,relatime,size=2912600k,nr_inodes=728150,mode=755,gid=1000)none on /config type configfs (rw,relatime)none on /dev/memcg type cgroup (rw,relatime,memory)注意到/dev/block/dm-0 on /system type ext4 (ro,seclabel,relatime,discard,data=ordered)这一行,后面括号有个ro,代表readonly!接下来尝试修改为可写(rw)状态:mount -o rw,remount /dev/block/dm-0 /system如果成功了,就试试将文件拷贝进去,失败了,例如提示:’/dev/block/dm-0’ is read-only,请继续阅读。这里参考Android O, failed to mount /system, /dev/block/dm-0 is read only,一顿操作!我这边是这样的:adb disable-verityadb reboot关闭验证是要重启设备的。执行重启后,继续:adb rootadb remountadb shell再执行mount发现结果跟刚才不一样了,找到有system的那一行发现这样的/dev/block/sde43 on /system type ext4 (rw,seclabel,relatime,discard,data=ordered)已经可写了,我试试拷贝进去。执行adb push /07e87b3d.0 /system/etc/security/cacerts/,出现以下结果:P750TM:/ whidy$ adb push /07e87b3d.0 /system/etc/security/cacerts//Users/whidy/07e87b3d.0: 1 file pushed. 0.1 MB/s (1947 bytes in 0.022s)应该就完成了。再去我的小米6手机里面的设置 > 更多设置 > 系统安全 > 加密与凭据 > 信任的凭据 > 系统里面看看,滚到最低部,ok,证书导入成功了。再去抓包看看我这文章是边写边记录的,现在可以看到https请求的抓包已经Ok啦最后我建议最后还原之前操作的disable-verity,这样操作一下:adb rootadb enable-verityadb reboot行了差不多就这些了。 ...

April 18, 2019 · 1 min · jiezi

vue单页面在微信下只能分享落地页的解决方案

实际上关键词叫微信pushState只能分享落地页更贴切一点应用场景:vue + vue-routervue-router使用hash模式(history模式没试过)不使用微信的js-sdk(因为我这个项目是可配置域名的商城,比较特殊,不能使用微信sdk)这个方案并不是最优秀的,会对性能造成一定的影响HTML5 history.pushStatevue-router的内部是通过history.pushState和history.replaceState实现的。但是iOS设备的微信浏览器不会去检测它们的变化。但是我们可以通过更新location.href让微信浏览器识别到当前的url。// vue-router/src/util/push-state.jsexport function pushState (url?: string, replace?: boolean) { saveScrollPosition() // try…catch the pushState call to get around Safari // DOM Exception 18 where it limits to 100 pushState calls const history = window.history try { if (replace) { history.replaceState({ key: _key }, ‘’, url) } else { _key = genKey() history.pushState({ key: _key }, ‘’, url) } } catch (e) { window.locationreplace ? ‘replace’ : ‘assign’ }}export function replaceState (url?: string) { pushState(url, true)}解决方法window.location.href = window.location.href,这段代码可以让微信记录当前的url,且不会刷新页面。可以在app.vue中watch $route在每次页面更新的时候执行一次。// app.vuewatch: { $route: { immediate: true, deep: true, handler(to) { // 微信浏览器判断 const WECHAT_BROWSER = navigator.userAgent.toLowerCase().includes(‘micromessenger’) // 解决iOS微信浏览器分享地址只能是落地页的问题,这个操作是不会刷新页面的,query参数改变也会执行 if (WECHAT_BROWSER) { // eslint-disable-next-line window.location.href = window.location.href } }},使用了上述方法可以解决这个问题,但是这会引出一个很奇葩的问题,在真机上进入http://192.168.1.5:8080和http://192.168.1.5:8080/#/这两个页面,其中有一个链接的bug依然存在。原因具体不清楚,经过测试可以在入口文件(main.js)中在页面还没有展示内容前刷新一次页面,即可解决这个问题。// main.js// 微信浏览器判断const WECHAT_BROWSER = navigator.userAgent.toLowerCase().includes(‘micromessenger’)// 在url插入的search参数,可以随意,但是必须要// 例:http://192.168.1.5:8080/?wx=1#/const wxQuery = ‘wx=1’const isRepeatQuery = location.search.includes(wxQuery)if (WECHAT_BROWSER && !isRepeatQuery) { const unit = (location.search && location.search !== ‘?’) ? ‘&’ : ‘?’ location.search += unit + wxQuery // 添加_wx_参数,该操作会刷新页面}上面的代码之所以要在hash前面加一个?wx=1参数,为了方便刷新页面给一个标志位判断是否已刷新。参数的key-value随意。 ...

April 15, 2019 · 1 min · jiezi

Python分析微信好友性别比例和省份城市分布比例,基于itchat模块

安装itchatpip install itchat使用新建wxfx.py,拷贝以下代码# -- coding: utf-8 --#导入模块from wxpy import *‘‘‘微信机器人登录有3种模式,(1)极简模式:robot = Bot()(2)终端模式:robot = Bot(console_qr=True)(3)缓存模式(可保持登录状态):robot = Bot(cache_path=True)’’’#初始化机器人,选择缓存模式(扫码)登录robot = Bot(cache_path=True)#获取好友、群、公众号信息robot.chats()#获取好友的统计信息Friends = robot.friends()print(Friends.stats_text())运行CMD->CD到wxfx.py所在目录运行,然后扫码登录结果Author:TANKINGWechat:likeyunba520Web:http://likeyunba.com

March 30, 2019 · 1 min · jiezi

移动端H5开发遇到的坑

微信分享签名错误invalid signaturevue单页应用history模式下微信分享一直提示签名错误invalid signature按照微信官网文档,已经引入jssdk,正确的配置js安全域名,后台开发人员生成的签名也通过微信签名工具验证,但是前端的自定义分享一直报签名错误,没有办法自定义分享,如果确保了哪些基本配置没有问题,并且签名也通过了微信签名工具验证,那么可能就是前端访问的url和后台生成签名的url不一致导致的签名错误前端如果是通过ajax将url传到后端获取签名,那么我们需要将当前页面除去’#‘hash部分的链接,并且需要encodeURIComponentlet url = location.href.split(’#’)[0]encodeURIComponent(url)正常来说这样就可以实现微信自定义分享了,但是单页应用路由切换了之后IOS端还是提示签名错误,安卓端没有问题这是因为history模式下视图是通过pushState来切换的,但是IOS微信客户端(安卓客户端已经修复了)不支持pushState的H5新特性,所以路由变化了但是微信浏览器获取到的url没有变化,右上角复制链接发现,微信记录的url还是第一次进入时的url,除非你手动刷新,或者使用window.location等页面跳转方法刷新,才能获取到最新的url解决的办法是页面进入的时候记录url,如果是iOS设备那么使用这个url获取微信签名router.afterEach(to => { sessionStorage.setItem(‘currentUrl’,window.location.href)})let url = encodeURIComponent(location.href.split(’#’)[0])if(system == “iOS” && sessionStorage.getItem(‘currentUrl’)) { url = encodeURIComponent(sessionStorage.getItem(‘currentUrl’).split(’#’)[0])}这个时候拿这个url去获取微信签名就是正确的了,该方法只适合IOS设备,只要获取签名的url和微信记录的url一致签名就是正确的往返缓存问题点击浏览器的前进和回退,有时候不会自动执行js,特别是在safari中,这与往返缓存(bfcache)有关系。解决方法 :window.onunload = function(){};如果是Vue单页应用,并且使用了keep-alive的话,页面也不会刷新,这时候一些接口请求等可以放在beforeRouteEnter方法中IOS端不支持new Date(“2019-01-01 00:00:00”) 这种格式这种写法new Date(“2019-01-01 00:00:00”)在安卓端是支持的,但是在IOS端不支持,会报NAN错误,所以需要把new Date(“2019-01-01 00:00:00”)改成new Date(“2019/01/01 00:00:00”)这种形式let date = ‘2019-01-01 00:00:00’date.replace(/-/g, ‘/’)微信二维码一个页面可能有多个二维码,但是长按识别二维码只能识别最后一个二维码,这个时候我们需要控制页面可视区域内只能出现一个二维码IOS中无法点击span,div 等默认无法点击的标签, IOS中监听click事件点击无效解决办法,添加 cursor: pointer;audio音频无法播放audio.play() 方法在安卓设备可以正常播放,但是在IOS客户端不能播放,在设置了audio的src之后,我们需要加上这一行代码audio.load() 去加载音频可以通过监听loadeddata方法看音频是否可以开始播放了,安卓设置在音频加载好了之后就开始播放,但是iOS端可能稍微有延迟,这个时候我们可以通过audio.currentTime获取到音频是否开始播放,这个值大于0就说明已经开始播放了IOS移动端click事件300ms的延迟响应fixed问题在ios8以下系统,当小键盘激活时,都会出现位置浮动问题,解决方法:只需要在中间部分外层div添加css样式position:fixed;top:50px; bottom:50px;overflow:scroll;

March 29, 2019 · 1 min · jiezi

了解一波网页端微信是如何登录的

前言工作之余突然对微信的网页版的协议通信感兴趣可以搞一波了解下。毕竟网页版容易抓,靠一个浏览器的开发者工具的Network就开始抓包解析了。这是我2019年03月写的文档。因为微信的协议可能随时存在变动,以下内容可以参考一波。本人爬虫的方法很简单,就是尽一切方法模仿被爬虫者的行为。该文档目前只写到获取最新消息。先记录一波。有空更新项目地址:楠尼玛大帝 / wxWebR(Java版)流程步骤(这里只说到成功登录到微信并获取最新消息,因为只是模仿到这里,其他的全部都已经清清楚楚只是看你调不调用而已了。该拿到的参数都有了)去获取一个uuid,可以根据这个uuid获取一张二维码登录的图片微信客户端扫描该二维码,在客户端确认登录。浏览器不停的调用一个接口,如果返回登录成功,则调用登录接口循环遍历一个检查是否有新消息的接口。如果新消息的接口返回有新消息的状态码去获取消息接口。(完)WebWechat API(这里也只说到成功登录到微信并获取最新消息。其他可以自行去抓包或者参考其他文档比如码云参考->python版(老版本)第一步获取UUID(参考方法 getUUID)API获取 UUIDurlhttps://login.wx.qq.com/jsloginmethodPOSTdataURL Encode(text/javascript)paramsappid: 应用ID 参考:wx782c26e4c19acffb redirect_uri 转发地址 参考:https://wx.qq.com/cgi-bin/mmw…fun: 应用类型 参考:new lang: 语言 参考:zh_CN : 时间戳 参考:当前时间毫秒级13位数的时间戳返回数据(String):window.QRLogin.code = 200; window.QRLogin.uuid = “xxx"注:目前看来参数除了 当前时间毫秒级13位数的时间戳 其他都是固定的值。在微信给的js里面index_ad43596.js里搜索API_jsLogin可以得到这些参数。而且大部分不理解参数都可以从这个js文件得到答案。显示二维码就不浪费时间直接就是拿第一步拿到的uuid拼接就是二维码地址:https://login.weixin.qq.com/q…{uuid}第二步等待扫码登录即微信确认登录API获取二维码扫描登录状态urlhttps://login.wx.qq.com/cgi-b…methodGET(text/javascript)paramstip :这个东西根据浏览器走的话就是第一次为1,后面都是为0,网上说是扫码状态 loginicon 参考:true uuid : 获取到的uuid _ : 当前时间毫秒级13位数的时间戳返回数据(String):window.code=xxx;xxx: 【未扫码的话】 -> window.code=408; 【手机扫码但是未登录】 -> window.code = 201; 【手机取消登录】 -> window.code=400; 【手机授权登录】 -> window.code=200;当返回200时:wechatLoginStatus:window.code=200; window.redirect_uri=“https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=XXX&uuid=XXX&lang=XXX&scan=XXX"; 当返回201时可以获取扫码用户头像的base64数据哦(好像没啥用)注: 像这种成功的话得到这种参数自己一定存起来,下一步肯定要用即ticket,lang,uuid,scan第三步扫描成功去获取你的登录凭据API获取登录凭据urlhttps://wx2.qq.com/cgi-bin/mm…methodGET(text/plain;charset=utf-8)paramsticket : ticket uuid : uuid lang : lang scan : scan fun : 参考:new version 参考:v2返回数据(XML):<error> <ret>0</ret> <message>OK</message> <skey>xxx</skey> <wxsid>xxx</wxsid> <wxuin>xxx</wxuin> <pass_ticket>xxx</pass_ticket> <isgrayscale>1</isgrayscale></error>核心数据点: skey, wxsid, wxuin, pass_ticket注: 切记,第三步会返回cookie,存下来,这里这个接口会得到cookie的。 cookie哪里用到我会说明的。第四步微信初始化API微信初始化urlhttps://wx2.qq.com/cgi-bin/mm…lang&pass_ticket=pass_ticketmethodPOSTdataJSON(application/json; charset=UTF-8)headerContent-Type: application/json; charset=UTF-8params{ BaseRequest: { Uin: wxuin, Sid: wxsid, Skey: skey, DeviceID: xxx, } }注:r这个参数是通过js的一个 ~new Date 这是一个类似二进制反转的一个,可自行百度或者打开控制台输出一下就知道了。DeviceID这个参数是一个简单js拼接出来的参数 “e”+(Math.random().toFixed(15)).substring(2, 17)返回数据(JSON):{ “BaseResponse”: { “Ret”: 0, “ErrMsg”: "” }, “Count”: 11, “ContactList”: […], “SyncKey”: { “Count”: 4, “List”: [ { “Key”: 1, “Val”: 635705559 }, … ] }, “User”: { “Uin”: xxx, “UserName”: xxx, “NickName”: xxx, “HeadImgUrl”: xxx, “RemarkName”: “”, “PYInitial”: “”, “PYQuanPin”: “”, “RemarkPYInitial”: “”, “RemarkPYQuanPin”: “”, “HideInputBarFlag”: 0, “StarFriend”: 0, “Sex”: 1, “Signature”: “Apt-get install B”, “AppAccountFlag”: 0, “VerifyFlag”: 0, “ContactFlag”: 0, “WebWxPluginSwitch”: 0, “HeadImgFlag”: 1, “SnsFlag”: 17 }, “ChatSet”: xxx, “SKey”: xxx, “ClientVersion”: 369297683, “SystemTime”: 1453124908, “GrayScale”: 1, “InviteStartCount”: 40, “MPSubscribeMsgCount”: 2, “MPSubscribeMsgList”: […], “ClickReportInterval”: 600000}第四步中获取 SyncKey, User 后面的消息监听用。第五步消息检查是否有新消息(这里要带上cookie)APIsynccheckurlhttps://webpush.wx2.qq.com/cg…skey&sid=wxsid&uin=wxuin&deviceid=xxx&synckey=Synckey&_=xxxmethodPOSTdataJSON(text/javascript)headerContentType: application/json; charset=UTF-8params 返回数据(String):window.synccheck={retcode:“xxx”,selector:“xxx”}retcode: 0 正常 1100 失败/登出微信 1101 在其他地方登录了微信 1102 无凭据或者凭据已失效selector: 0 正常 2 新的消息 7 进入/离开聊天界面注: deviceid 和上面的DeviceID这个参数是一样的:一个简单js拼接出来的参数 “e”+(Math.random().toFixed(15)).substring(2, 17)我们叫他时间戳取反吧 _是一个当前时间毫秒级13位数的时间戳 第六步获取最新消息(要带上Cookie)APIwebwxsyncurlhttps://wx2.qq.com/cgi-bin/mm…wxsid&skey=SkeymethodPOSTdataJSON(text/plain)headerContentType: application/json; charset=UTF-8params{ BaseRequest: { Uin: User下的Uin, Sid: wxsid, Skey: skey, DeviceID: DeviceID}, SyncKey: syncKey, rr: 时间戳取反 }返回数据(JSON):{ ‘BaseResponse’: {‘ErrMsg’: ‘’, ‘Ret’: 0}, ‘SyncKey’: { ‘Count’: 不确定个数, ‘List’: [ {‘Val’: 636214192, ‘Key’: 1}, … ] }, ‘ContinueFlag’: 0, ‘AddMsgCount’: 1, ‘AddMsgList’: [ { ‘FromUserName’: ‘’, ‘PlayLength’: 0, ‘RecommendInfo’: {…}, ‘Content’: “”, ‘StatusNotifyUserName’: ‘’, ‘StatusNotifyCode’: 5, ‘Status’: 3, ‘VoiceLength’: 0, ‘ToUserName’: ‘’, ‘ForwardFlag’: 0, ‘AppMsgType’: 0, ‘AppInfo’: {‘Type’: 0, ‘AppID’: ‘’}, ‘Url’: ‘’, ‘ImgStatus’: 1, ‘MsgType’: 51, ‘ImgHeight’: 0, ‘MediaId’: ‘’, ‘FileName’: ‘’, ‘FileSize’: ‘’, … }, … ], ‘ModChatRoomMemberCount’: 0, ‘ModContactList’: [], ‘DelContactList’: [], ‘ModChatRoomMemberList’: [], ‘DelContactCount’: 0, …}注 这一块比较要特别注意,得到消息后发现返回的信息也是有SyncKey 这个要更新一波直接拿下来替换自己的旧的,不然第五步检查消息是会出现问题就是刷的特别快,而且消息是不正确的。因为真正成功访问的到是微信的请求不会立即返回,一个请求会跑的比较久至少几十秒,因为防止疯狂遍历,不用担心因为一旦有数据返回微信服务器会立刻返回数据给你进入下一阶段的循环。这一步也是比较坑的就是SyncKey要记得更新就行了。还有一个很骚的点就是_这个参数虽然是毫秒级的13位时间戳,但是在微信第一次获取后他不会再去new了,就是一直+1+1;致谢本项目受到以下项目的启发:Zhao / wxBot ...

March 29, 2019 · 2 min · jiezi

Python微信防撤回,基于itchat模块

有时候,女神发来一条消息,说约你看电影,她考虑了一下,又撤回了,不约你了…而你又想知道她究竟发了什么,该怎么办?微信防撤回了解一下。环境要求Python3 电脑安装itchatpip install itchat使用代码新建chehui.py,拷贝以下代码#!/usr/bin/env python3# -- coding: utf-8 --author = ‘jiangwenwen’import itchatfrom itchat.content import import timeimport reimport osprint(“该程序由里客云资源站开发,网址:likeyunba.com”)print(“作者:TANKING”)print(“打开程序会弹出一个二维码,微信扫码”)print(“如果二维码弹不出,那就在你这个程序的同一个目录下找到QR.png双击打开扫码”)print(“扫码后,出现Start auto replying就可以实时监控消息了…")msg_information = {}# 针对表情包的内容face_bug = None@itchat.msg_register([TEXT, PICTURE, FRIENDS, CARD, MAP, SHARING, RECORDING, ATTACHMENT, VIDEO], isFriendChat=True, isMpChat=True)def handle_receive_msg(msg): global face_bug # 接收消息的时间 msg_time_rec = time.strftime("%Y-%m-%d %H:%M:%S”, time.localtime()) # 在好友列表列表中查询发送信息的好友昵称 msg_from = itchat.search_friends(userName=msg[‘FromUserName’])[‘NickName’] # 信息发送的时间 msg_time = msg[‘CreateTime’] # 每条信息的ID msg_id = msg[‘MsgId’] # 储存信息的内容 msg_content = None # 储存分享的连接,比如分享的文章和音乐 msg_share_url = None # 如果发送的消息是文本或者好友推荐 if msg[‘Type’] == ‘Text’ or msg[‘Type’] == ‘Friends’: msg_content = msg[‘Text’] print(msg_content) # 如果发送的消息是附件,视频,图片,语音 elif msg[‘Type’] == ‘Attachment’ or msg[‘Type’] == ‘Video’ \ or msg[‘Type’] == ‘Picture’\ or msg[‘Type’] == ‘Recording’: # 内容为下载文件名 msg_content = msg[‘FileName’] msg‘Text’ # 如果消息是推荐的名片 elif msg[‘Type’] == ‘Card’: # 内容是推荐人的昵称和性别 msg_content = msg[‘RecommendInfo’][‘NickName’] + ‘的名片’ if msg[‘RecommendInfo’][‘Sex’] == 1: msg_content += ‘性别为男’ else: msg_content += ‘性别为女’ print(msg_content) # 如果消息为分享的位置信息 elif msg[‘Type’] == ‘Map’: x, y, location = re.search( “<location x="(.?)" y="(.?)".label="(.?)".”, msg[‘OriContent’]).group(1, 2, 3) if location is None: # 内容为详细地址 msg_content = r’纬度->’ + x.str() + “经度->” + y.str() else: msg_content = r"" + location # 如果消息是分享的音乐或者文章,详细的内容为文章的标题或者分享的名字 elif msg[‘Type’] == ‘Sharing’: msg_content = msg[‘Text’] msg_share_url = msg[‘Url’] print(msg_share_url) face_bug = msg_content # 将信息存储在字典中,每一个msg_id对应一条消息 msg_information.update( { msg_id: { “msg_from”: msg_from, “msg_time”: msg_time, “msg_time_rec”: msg_time_rec, “msg_type”: msg[‘Type’], “msg_content”: msg_content, “msg_share_url”: msg_share_url } })#这个是用于监听是否有friend消息撤回@itchat.msg_register(NOTE, isFriendChat=True, isGroupChat=True, isMpChat=True)def information(msg): # 这里如果这里的msg[‘Content’]中包含消息撤回和id,就执行下面的语句 if ‘撤回了一条消息’ in msg[‘Content’]: old_msg_id = re.search("&lt;msgid&gt;(.*?)&lt;/msgid&gt;", msg[‘Content’]).group(1) # 得到消息 old_msg = msg_information.get(old_msg_id) print(old_msg) # 如果发送的是表情 if len(old_msg_id)<11: itchat.send_file(face_bug, toUserName=‘filehelper’) # 发送撤回的提示给文件助手 else: msg_body = “【”\ + old_msg.get(‘msg_from’) + “撤回了】\n”\ + old_msg.get(“msg_type”) + “消息:” + “\n”\ + old_msg.get(“msg_time_rec”) + “\n”\ + r"" + old_msg.get(“msg_content”) # 如果分享的文件被撤回了,那么就将分享的url加在msg_body中发送给文件助手 if old_msg[‘msg_type’] == “Sharing”: msg_body += “\n就是这个链接>” + old_msg.get(‘msg_share_url’) # 将撤回消息发送到文件助手 itchat.send_msg(msg_body, toUserName=“filehelper”) # 有文件的话也要将文件发送回去 if old_msg[“msg_type”] == “Picture”\ or old_msg[“msg_type”] == “Recording”\ or old_msg[“msg_type”] == “Video”\ or old_msg[“msg_type”] == “Attachment”: file = “@fil@%s” % (old_msg[‘msg_content’]) itchat.send(msg=file, toUserName=‘filehelper’) os.remove(old_msg[‘msg_content’]) # 删除字典旧信息 msg_information.pop(old_msg_id)itchat.auto_login(hotReload=True)itchat.run() CMD运行即可。考虑到有一些人没有Python环境,我已经打包成可执行文件了,直接双击exe就可以在电脑运行。微信扫码:TANKINGHTTP://LIKEYUNBA.COM2019-3-28 ...

March 28, 2019 · 2 min · jiezi

Laravel + Laravel-echo + EasyWeChat 实现微信扫码登录

扫码登录成为一种日趋流行的登录方式,它具有较高的安全性,同时又使我们从记忆大量的账号密码并手动输入的繁琐流程中解脱出来,有些平台甚至无账号也能扫码登录,连注册的麻烦都省了。对于接入微信开放平台的公众号应用来说,实现扫码登录是相当容易的,有 EasyWeChat SDK 加持,再按着官方的文档一把梭,很快就能完成。然而本文所要讨论的是另一种情况,有时候出于某些原因,自己的公众号不能接入开放平台,但又想进行微信扫码登录,这种情况下显示就不能再换官方的套路来了。但只要我们稍作变通,就能实现这一需求。基本思路:登录页显示微信二维码(使用 EasyWeChat SDK 创建,短时效的临时二维码)用户扫码后推送消息到服务器接口,接口中根据业务情况进行判断处理,符合条件时触发 WechatScanLogin 事件WechatScanLogin 事件实现 ShouldBroadcast 接口,所以当它被触发时也会向指定的频道进行广播前端 laravel-echo 监听频道中用户扫码登录的消息并进行处理以下就来介绍一下具体实现,先放效果图。具体实现配合本文,我创建了一个简单的示例项目,有兴趣的可以克隆下来,配合源码一起服用,效果更佳。项目地址:https://github.com/tianyong90/laravel-qrcode-login首先当然是创建 Laravel 项目,同时安装前后端依赖前端最主要依赖是 laravel-echo 和 socket.io-client前端监听事件广播是关键,我们需要一个 websocket 服务端,Laravel 官方文档在介绍消息广播时提到了 Pusher 和 laravel-echo-server。因为我使用 laradock 作为开发环境,其中内置了 laravel-echo-server 容器,十分方便,所以决定直接用它。实际上也可以使用 Pusher 服务,那么则需要安装 pusher.js 替代 socket.io-client,同时在 .env 中修改相关配置配置项目主要是配置数据库和 redis 连接,然后把 BROADCAST_DRIVER 设置为 redis(这一点很重要,如果使用 pusher 则需要修改为 pusher)如果 QUEUE_CONNECTION 设置为 redis 了,则需要记得启动队列 worker.启动 laravel-echo-server因为使用 laradock,所以只需要启动时带上 laravel-echo-server 参数就可以了,进入 laradock 目录docker-compose up -d nginx php-worker nginx mysql redis laravel-echo-server创建 WechatScanLogin 事件php artisan make:event WechatScanLoginclass WechatScanLogin implements ShouldBroadcast{ use Dispatchable, InteractsWithSockets, SerializesModels; public $token; /** * Create a new event instance. * * @param $token / public function __construct($token) { $this->token = $token; } /* * Get the channels the event should broadcast on. * * @return \Illuminate\Broadcasting\Channel|array */ public function broadcastOn() { return new Channel(‘scan-login’); }}上面最关键的就是事件要实现 ShouldBroadcast 接口并在 broadcastOn 方法中指定要广播的频道。WechatScanLogin 的公开属性 token 会自动包含在广播数据中。对接微信消息服务器laravel-wechat 的相关配置和对接,请阅读 EasyWeChat SDK 官方文档。接收扫码的消息并进行相关处理。public function serve(){ $app = app(‘wechat.official_account’); $app->server->push(function ($message) { if ($message[‘Event’] === ‘SCAN’) { $openid = $message[‘FromUserName’]; $user = User::where(‘openid’, $openid)->first(); if ($user) { // TODO: 这里根据情况加入其它鉴权逻辑 // 使用 laravel-passport 的个人访问令牌 $token = $user->createToken($user->name)->accessToken; // 广播扫码登录的消息,以便前端处理 event(new WechatScanLogin($token)); \Log::info(‘haha login’); return ‘登录成功!’; } return ‘失败鸟’; } else { // TODO: 用户不存在时,可以直接回返登录失败,也可以创建新的用户并登录该用户再返回 return ‘登录失败’; } }, \EasyWeChat\Kernel\Messages\Message::EVENT); return $app->server->serve();}使用 EasyWeChat 创建临时二维码并在页面中显示。public function index(){ $wechat = app(‘wechat.official_account’); $result = $wechat->qrcode->temporary(‘foo’, 600); $qrcodeUrl = $wechat->qrcode->url($result[’ticket’]); return view(‘index’, compact(‘qrcodeUrl’));}<img src={{ qrcodeUrl }} />>前端使用 laravel-echo 订阅对应的微信扫码登录事件,接收其中的 token 并存入本地存储作为判断是否登录的凭据,同时这个 token 也将作为访问后端 api 的授权依据。注意前面的代码中,使用了 laravel-passport 生成这个个人访问令牌,如果不了解这部分原理,请查阅 Laravel 官方文档。import Echo from ’laravel-echo’import io from ‘socket.io-client’window.io = iolet EchoInstance = new Echo({ broadcaster: ‘socket.io’, host: window.location.hostname + ‘:6001’,})EchoInstance.channel(‘scan-login’).listen(‘WechatScanLogin’, e => { localStorage.setItem(‘my_token’, this.token) // 其它处理 })总结至此,简单的扫码登录就完成了。当然,本文示例代码不怎么优雅、流程可能也有不完善的地方,主要是为了提供一个大致思路。有了这个思路,我们可以实现其它诸如扫码签到、扫码投票等各种功能,具体如何就看大家的创意了。最后放上个人博客地址:https://tianyong90.com/, 欢迎各位大佬批评指正。 ...

March 19, 2019 · 2 min · jiezi

Python清理微信僵尸粉

需求要想知道你微信哪些人删了你其实很简单,只需要给对方发送消息,提示好友已开启好友验证或者对方拒绝接收你的消息,则代表您已被对方删除或者拉入黑名单。但是,好友多的情况下,效率就低,尽管是建微信群和转账这种方法已经不实用,效率很低!那么我们可以通过Python,自动向还有发送消息,如果发送失败,则代表对方删除我或者拉黑了!我们还有一个需求就是,不打扰到别人!所以绝对不能随便向别人群发内容,现在有一个代码,是发送给别人收不到的,这个代码就可以实现免打扰给别人发送消息。脚本运行环境1、电脑2、Python3环境WIN+R打开运行,输入cmd进入windows命令行工具输入以下命令,安装wxpy脚本pip3 install wxpy下载wechat_clear.pycurl -fsSL https://raw.githubusercontent.com/ruicky/python-awsome/master/wechat_clear/wechat_clear.py -o wechat_clear.py执行wechat_clear.pypython wechat_clear.py然后就会弹出一个二维码给你扫码,扫码后,就开始检测了!检测截图只要检测到僵尸粉,你的微信就会出现这个

March 15, 2019 · 1 min · jiezi

“知否精选”,小程序版本知乎日报诞生笔记

引子Question: 为什么要小程序版本的“知乎日报”?Answer: 国内大部分成熟的应用一般都会有对应的小程序版本的客户单,但是“知乎日报”没有。而我自己是非常喜欢小程序的,索性就自己做一个。至于知乎官方为什么不实现这个小程序客户端我也不得而知,我通过在微信公众号后台查询得知 “知乎日报”这个名字的小城是已经被注册了,如下图:根据现在的微信小程序名称命名的审核规则,像“知乎日报”这样名称的小程序主体一定是在知乎官方手中的。总之,不管怎么说,既然知乎官方没有做,那么我就来做一个吧。1. 关于知否精选本项目的初始版本已经正式发布在微信小程序,名称为 “知否精选”(官方名称知乎日报已经被注册,所以选择了这么一个名字)。除此之外,本项目的源代码也已经开源,源代码非常的简单,可以供想要学习小程序的同学们参考练手,地址 https://github.com/llyer/wech…。在开始实现之前,我在网站搜索了一下,找到了知乎日报的 API,仓库的地址在下面https://github.com/izzyleung/…API 的地址有了,接下来就是代码,同样在 github 上已经有了知乎日报的小程序版本代码,但是已经很久没有更新了,而且之前的作者也在仓库里面表示不再更新,仓库地址如下https://github.com/myronliu34…知否精选的主要资料来源如上。2. 目前实现的功能1. 加载文章列表2. 查看文章内容这两个功能是知乎日报最核心的功能,都已经实现。当然在发开过程中也遇到了一些问题,目前已经有了一些已知的BUG,也正在紧急修复中。例如知乎的API中返回的文章内容是富文本格式的,部分文章的格式解析可能没有做到完全的适配。如果对于本项目感兴趣的同学可以到 https://github.com/llyer/wech… 点个 Star,如果发现了有什么问题,欢迎提Issue。如果你只是单纯的喜欢这个小程序版本的知乎日报。请在微信小程序搜索 “知否精选”即可打开本程序,或者使用扫描下方二维码打开 “知否精选”,如果遇到问题,请在下方留言告诉我,我会尽快解答。

March 14, 2019 · 1 min · jiezi

微信下调试H5页面

Android端微信1、首先打开,http://debugx5.qq.com 或者扫描下面二维码2、打开微信 TBS 调试3、然后在谷歌浏览器地址栏输入chrome://inspect/#devices出现如下界面4、点击想要调试的页面下的inspect即可

March 6, 2019 · 1 min · jiezi

js判断微信内核浏览器

var ua = navigator.userAgent.toLowerCase();if(ua.match(/MicroMessenger/i)==“micromessenger”) { alert(“微信”);} else { alert(“不是微信”);

March 5, 2019 · 1 min · jiezi

微信隐藏下导航栏

代码: $(’#Zl’).html(’<iframe width=“100%” id=“rid” src="<?php echo $ff[“url”];?>" frameborder=“0”></iframe>’); $(document).ready(function () { function fix_height() { $("#rid").attr(“height”, (($(window).height()) - 5) + “px”); } $(window).resize(function () { fix_height(); }).resize() });

February 23, 2019 · 1 min · jiezi

微信小程序

微信小程序小程序前端Hybrid解决方案,渲染线程与脚本线程(逻辑层)是分开,环境包括IOS和Android的微信客户端,以及开发者工具.缺点:不能订阅,不能转发朋友圈,不能主动推送消息.检索具有局限性,不能模糊搜索.小程序的代码组成:index.wxml和index.wxss和index.wxs和index.json和index.jsWXML:一种标签语言,结合组件,事件,构建出页面结构.所有的wxml标签都支持的属性有id,class,style,hidden,data,bind/catchWXSS:rpx作为尺寸单位,@import url(’.//.a.wxss’)实现样式引用。支持.class #id element :after :beforeJSON:一种数据格式,静态配置.语法: { “pages”: [], “window”: {}},注意在JSON中无法使用注释JavaScript:ECMAScriptScript(语法+类型+语句+关键字+操作符+对象)+小程序框架+小程序API</p>小程序的宿主环境:分为逻辑层(JS)与渲染层(WXML+WXSS),页面由组件,API,事件,兼容性构成。</p>小程序的API:宿主环境提供丰富的API,所有的API都挂在wx对象下(除了Page/APP等特殊的处理器)。 wx.set开头的API是写入数据到宿主环境的接口。 wx.get开头的API是获取数据到宿主环境的接口。 小程序要求开发者服务器提供HTTPS服务的接口 接口回调说明:success 成功 fail 失败 complete 接口调用结束的回调函数 小程序的场景应用:Flex布局 界面的交互反馈 微信登录 本地数据缓存 设备能力微信登录: wx.login生成一个带有时效性的凭证,发送code到服务器,到微信服务器获取微信用户身份id,绑定微信用户身份和业务用户身份,业务登录凭证返回SessionId小程序目录: app.json(小程序公共配置)当前小程序的全局配置,包括小程序所有页面路径,界面表现,网络超时时间,底部tab等. app字段–用于描述当前小程序所有页面路径. window字段–定义小程序所有页面的顶部颜色,文字颜色等. project.config.json(工具配置):配置开发者工具. page.json(页面配置):用来表示pages/logs目录下的logs.json这类和小程序页面相关的配置. app.js(必需),小程序逻辑 app.wxss(非必需):小程序公共样式表page页面: .json后缀的JSON配置文件 ,提供页面配置.非必须. .wxml必需文件,采用MVVM的开发模式,JS管理状态,通过一种模板语法来描述状态和界面结果的关系. .wxss后缀的Wxss样式文件 ,采用大部分CSS特性,仅支持部分css选择器,在底层支持尺寸单位rpx,提供全局样式(app.wxss)和局部样式(page.wxss),非必须. .js后缀的JS脚本逻辑文件,必需文件.可上传的的文件白名单:wxss png jpg jpeg gif svg json cer mp3 aac m4a mp4 wav ogg slik逻辑层(App Service) –小程序框架的逻辑层,采用JavaScript引擎为开发者提供JavaScriptd代码的运行环境以及微信小程序的特有功能(如:增加APPh和Page方法),逻辑层将数据处理后发送给视图层且接受视图层的反馈. –API –模块化 –路由 –注册页面 –场景值 注册程序视图层: 由于WXML和WXSS和WXS和组件展示,由组件来进行展示,主要作用是将逻辑层的数据反应成视图,同时将视图层的事件发送给逻辑层.事件:touchstart touchmove touchcancel touchend tap longpress longtap 宿主环境:小程序的运行环境分成渲染层(WXML和WXSS)和逻辑层(JavaScript)分别由两个线程管理,渲染层的界面使用WebView继续渲染,逻辑层使用JSCore线程运行脚本.小程序会有多个页面,也就有多个WebVIew线程.所有线程的通信经由微信客户端做中转.所有页面的脚本逻辑都跑同一个JsCore线程,页面使用setTimeout或者setInterval的定时器,跳转其他页面时,这些定时器并没有被消除.

February 22, 2019 · 1 min · jiezi

单页面路由工程使用微信分享及二次分享解决方案

wxShare 说明文档单页面路由工程使用微信分享及二次分享解决方案很多人在单页面工程中使用weixin jsSDK时 ,第一次调用正常, 路由切换时发现调用分享配置报错, 此时忽略了一点 ,在单页面路由的 url 发生变化时, 需要重现调用微信jsSDK分享配置;wxShare除适用于 Vue 单页工程外, 也可以使用与其他单页工程例如 React,本示例主要展示如何在 Vue中使用;微信 jssdk调用基本原理1. (初始化页面,划重点)掉用 api 获取当前页面 url 授权的签名2. 配置微信分享 jssdk3. 路由切换时, 重新执行步骤21. 快速使用, 只需三步示例参见 demo下 src/main.js在工程入口文件引入 wxShare 文件/*************** 步骤一 引入 微信 jssdk /let appInit=0;import wx from ‘weixin-js-sdk’;//配置授权apiwxShare.config.jsSDKAuth=’/api/mobile/WeiXin/ecstoreSendJsSdk’;/*** 第二步 初始化微信分享 /if (location.host != “localhost:8080”) { let sign_url = location.href.split("#")[0]; appInit++; if (wx) { wxShare.initWxShare(sign_url); }}/*** 第三步 监听路由重置微信分享为默认 /router.afterEach(route => { let url=location.href.split("#")[0]; if (!store) return; if(appInit>1){ wxShare.resetWxShareConfig(); } appInit++;})/*** end 分割线 ************/2. wxShare提供的方法2.1 initWxShare()初始化微信分享, 此时会调用内部方法 wxShareAuth, 请求 api 授权当前页面 url;2.2 updateWxShareConfig()更新微信分享配置内容, 例如, 在某个事件上主动调用此方法, 来更改微信分享配置的标题, 简述,链接或者封面图2.3 resetWxShareConfig()通常情况下, 在路由发生变化时, 希望已被更改过的分享配置, 重新重置为默认分享配置2.4 configWXJSSDK();调用微信jsSDK 完成分享配置3. wxShare.config属性配置配置名称属性值默认值jsSDKAuthString’‘shareSignObject下文shareSigndefaultWxShareConfigObject下文defaultWxShareConfigwxShareConfigObject下文wxShareConfig3.1 shareSign提供的配置{ appid:"", jsapi_ticket:"", nonceStr:"", signature:"", timestamp:’’, url:"",}3.2 defaultWxShareConfig{ title: “默认分享配置title”, desc: “默认分享配置desc”, link: location.href.split("#")[0], imgUrl: ‘https://res.wx.qq.com/a/wx_fed/weixin_portal/res/static/img/dNEBuK6.png', jsApiList:[‘onMenuShareTimeline’, ‘onMenuShareAppMessage’, ‘hideMenuItems’, ‘closeWindow’], hideMenuList:[‘menuItem:editTag’, ‘menuItem:delete’, ‘menuItem:originPage’, ‘menuItem:readMode’, ‘menuItem:openWithQQBrowser’, ‘menuItem:openWithSafari’, ‘menuItem:share:email’, ‘menuItem:share:brand’]}3.3 wxShareConfigwxShareConfig:{}其他/wxShare.js 为插件源码文件, 可根据自己需求自行更改demo 工程只需 clone 本工程,npm installnpm run servenpm依赖插件weixin-js-sdkaxios ...

February 21, 2019 · 1 min · jiezi

利用网页版微信API做一个微信机器人

本文不涉及到 AI 的知识,如果你是冲着 AI 来的,那么可能会让你失望了.前一阵子一个朋友找我,问我能不能搞一个微信自动加好友的软件,(在普通人眼里,程序员就是专门写木马病毒外挂软件的三流黑客.不会写那就连三流都不是.所以为了证明我是三流黑客,我随便百度了两个现成的给他.本来事情到这里应该结束了的,不过本着探索的精神,想顺便了解一下这种外挂的原理,于是百歌谷度了一下,最终原理没找到,倒是找到几个有意思的 github 仓库,利用网页版的微信 API 做第三方微信.先看个效果?<img src=“https://raw.githubusercontent…; width=“300” /><img src=“https://raw.githubusercontent…; width=“300” />步骤我们看看大致步骤获取 UUID根据 UUID 获取二维码扫码登陆, 获取登陆信息拿登陆信息换初始化数据拿数据初始化获取好友列表和消息列表发送消息以下为具体过程,不感兴趣的可以直接拉到末尾查看源码仓库需要注意的是,每一步的请求所使用的方法(POST/GET) 和 Content-Type 都是不一样的,下面我都有标注,如果有请求不通的请参考 gtihub 源码.一、获取 UUID接口地址 https://wx.qq.com/jslogin请求方法 POST参数类型(content-type) application/x-www-form-urlencoded参数{ appid: ‘wx782c26e4c19acffb’, fun: ’new’, lang: ‘zh_CN’, _: new Date().valueOf()}除了最后一个当前时间戳不是固定的,其他的3个参数都是写死的,照抄即可,调用成功的话,会到一个字符串 window.QRLogin.code = 200; window.QRLogin.uuid = “obizONtqZA==”;, 需要自己想办法截取到 window.QRLogin.uuid = 后面的那串字符,即 UUID.二、获取二维码这一步很简单,有了 UUID 后,我们可以直接请求 ‘https://wx.qq.com/qrcode/' + UUID 获取到二维码. 获取到二维码以后,先别急着去扫描二维码,因为我们要先去监听二维码的扫描状态,这样我们才能知道什么时候被登陆.请求方式 GET 无需参数三、监听二维码的扫描结果接口地址 https://wx.qq.com/cgi-bin/mmw…请求方法 GET参数类型(content-type) application/x-www-form-urlencoded参数{ tip: 0, uuid: ‘obizONtqZA==’, : new Date().valueOf(), loginicon: true}tip 取值 0 或 1, 监听分2个阶段,第一阶段,监听用户是否扫码,tip 为 0,第二阶段,监听用户是否在微信上点确认登陆,tip 为 1.uuid 就是第一步获取到的那个 UUID 当前时间戳loginicon 我猜应该是否扫码完返回用户头像,都填 true 即可.返回结果,当你扫描二维码的时候,接口会返回你一个这样的对象{ ‘window.code’: 201, ‘window.userAvatar’: 头像的 base64 地址}得到的 code 是 201, 说明已扫码,但并不代表已登陆,还需要继续监听是否在手机微信上点击 确认登陆 按钮(重复上面步骤,把 参数里的 tip 改为 1 即可)这步如果成功的话,会返回一个如下对象{ ‘window.code’: ‘200’, ‘window.redirect_uri’: ‘https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=ARD37_ikx-Kakd2i0W-f-E7q@qrticket_0&uuid=4f6yOkV4AA==&lang=zh_CN&scan=1548300672' }}四、获取初始化数据(敏感数据)上一步获取到的数据里面的 window.redirect_uri 里包含了一个 url 和一些 查询参数,直接请求这个地址好像没办法成功,需要将 url 和 参数拆分,然后加入其他参数接口地址 就是上面的 url请求方法 GET参数类型(content-type) application/x-www-form-urlencoded参数{ ticket: 上面得到的 ticket, uuid: 上面得到的 uuid, lang: ‘zh_CN’, // 固定 scan: 上面得到的 scan, fun: ’new’ // 固定}这一步的返回的头部里面,会有个 cookie ,需要存起来,接来来得到请求头里面要带上这个 cookie,另外就是一个 xml 格式的 敏感的信息,也是要存起来.tip: xml 格式可以用 xml2js 转换成 json.五、初始化呼,到这一步,终于接近登陆成功了,只需再调用以下接口,初始化以下接口地址 https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=${~(new Date().valueOf())}请求方法 POST参数类型(content-type) application/json参数{ BaseRequest: { DeviceID: ’e747337466044216’, // 这个好像随便填都可以 Sid: 上一步获取到的 wxsid, Uin: 上一步获取到的 wxuin, Skey: 上一步获取到的 skey }}这里有 2 个地方跟之前不同的,第一是地址后面要跟一个时间戳,而且这个时间戳还要按位取反,第二个是请求参数是放在 BaseRequest 下面,而不是对象的一级属性下面.返回的数据里面有 2 个数据需要保存起来,一个是 data.SyncKey, 一个是 res.data.User.UserName,后面都会用到到此才真正完成登陆,下面如果你不需要好友列表的话,可以直接收取消息了六、检测新消息接口地址 https://webpush.wx.qq.com/cgi…请求方法 GET参数类型(content-type) application/json参数let time = new Date().getTime()let synckey = ‘’let sk = data.SyncKey.List || [] // data.SyncKey 就是上一步获取到的那个for (let i = 0; i < sk.length; i++) { synckey += ${sk[i].Key}_${sk[i].Val} if (i !== sk.length - 1) synckey += ‘|’}// 传递的参数{ r: time, sid: 第四步拿到的 wxsid, uin: 第四步拿到的 wxuin, skey: 第四步拿到的 skey, deviceid: ’e747337466044216’, // 同上一步 synckey: synckey, _: time}返回内容的 data 里面 包含如下内容window.synccheck={retcode:“0”,selector:“2”}如果 selector 是 2, 说明有新消息,走下一步,获取消息内容七、获取消息内容接口地址 https://wx.qq.com/cgi-bin/mmw…请求方法 POST参数类型(content-type) application/json参数{ BaseRequest: { Uin: 第四步拿到的 wxuin, Sid: 第四步拿到的 wxsid, Skey: 第四步拿到的 skey, DeviceID: ’e747337466044216’, // 同上一步 }, SyncKey: data.SyncKey, // 还记得上一步我们费尽千辛万苦转换这个数据吗? 你没看错,这里不需要转换,就是这么神奇 rr: ~(new Date().valueOf())}返回结果里面有个 data.AddMsgList 就是消息列表了,还有个 data.SyncCheckKey 就是下次请求的时候用的 SyncKey, 每次都会变的.AddMsgList 是一个数组,里面可能包含多条消息,消息的自动比较多,就不一一说明了,这里说说 2 个比较重要的字段,其他的字段有兴趣的可以自己打印出来看一下.FromUserName 对方的微信名,说是微信名,其实是一个 @ 或 @@ 开头的内部的id, 完全不可读,据我猜测 @ 开头的应该是普通好友, @@ 开头的是群或者公众号之类的Content 消息内容有了消息内容,和发消息的人,我们就可以回复对方,不过回复什么? 当然不可能写一大堆 if else 或者 switch case 去适应各种情况,不妨网上搜索一下 价值一个亿的ai代码 哈哈哈八、获取自动回复内容这边我用的是图灵机器人的 API 地址,当然你也可以用其他的.接口地址 http://openapi.tuling123.com/…请求方法 POST参数类型(content-type) application/json参数{perception: { inputText: { text: ‘待回复的消息’ }},userInfo: { apiKey: tulingApiKey, // 在图灵官网申请 userId: tulingUserId // 同上}你要是懒得去申请的话,可以在我的项目里面复制, 在 src/global.js 里面,在返回的内容里面 data.results[0].values.text 下面可以看到图灵给你生成的自动回复内容(results是一个数组,支持一次回复多条)九、回复消息拿到自动回复以后,我们只需要把它发给你的好友,即完成一次自动对话.接口地址 https://wx.qq.com/cgi-bin/mmw…请求方法 POST参数类型(content-type) application/json参数let timeStamp = new Date().getTime() + ’’ + (9000 * Math.random() + 1000){ BaseRequest: { Uin: 同上, Sid: 同上, Skey: 同上, DeviceID: 同上 }, Msg: { Type: 1, // 消息类型 1 是文字消息,其他的暂时没用过 Content: ‘回复的内容’, FromUserName: ‘你的用户名,在第五步有拿到’, ToUserName: ‘对方的微信名 第七步的 FromUserName’, LocalID: timeStamp, ClientMsgId: timeStamp}发送成功的话,会返回如下内容{ BaseResponse: { Ret: 0, ErrMsg: ’’ }, MsgID: ‘2033517278669301361’, LocalID: ‘’}好了,这样我们的一个自动回复机器人就完成了.完整的代码在这里广告时间我们40人的前端团队常年招兵买马中,在厦门的和想来厦门的童鞋们,不要吝惜你的简历,使劲砸过来 邮箱:atob(‘bnVveWFAZ2FvZGluZy5jb20=’), 期待你一起来稿事对本文有意见或者建议,请尽量在 github 上提 issue, 最近比较忙,比较不怎么逛社区 ...

January 25, 2019 · 2 min · jiezi

vue 微信分享(实战)

今天碰到了微信分享的需求,总体上来讲还是比较简单的,但是还是碰到了一个假想的坑(真的是假想),???? api地址1. 思路步骤一:绑定域名引入JS文件通过config接口注入权限验证配置(反正微信的东西都有这一步)????通过ready接口处理成功验证通过error接口处理失败验证2. 实现1.绑定域名,在公众号后台绑定域名,所以最后的测试一定要是线上(环境要么用内网穿透,这样容易调试,不用每一次都发测试环境)2.在index.html文件里面引入http://res.wx.qq.com/open/js/jweixin-1.4.0.js // 注意协议3.通过config接口注入权限验证配置, 下面五个参数都是通过请求后台,后台返回给你的。 注意: 当前页面的url是要在这个接口里给后台的,它们才能生成可用的, 签名算发, url的格式如下: url(当前网页的URL,不包含#及其后面部分),所以要注意vue-router的模式(通过config接口注入权限验证配置,jsApiList是调用的事件,api文档附录2里面有) wx.config({ debug: false, // 是否开启调试模式 appId: appId, //appid timestamp: timestamp, // 时间戳 nonceStr: nonceStr, // 随机字符串,只有这个是驼峰???? signature: signature, // 签名 jsApiList: [ “onMenuShareTimeline”, “onMenuShareAppMessage”, “onMenuShareQQ”, “onMenuShareWeibo”, “onMenuShareQZone” ] // 需要使用的JS接口列表 }); // 判断当前客户端版本是否支持指定JS接口 ,这步可无 wx.checkJsApi({ jsApiList: [ “onMenuShareTimeline”, “onMenuShareAppMessage”, “onMenuShareQQ”, “onMenuShareWeibo”, “onMenuShareQZone” ], // 需要检测的JS接口列表,所有JS接口列表见附录2, success: function(res) { console.log(res); // 以键值对的形式返回,可用的api值true,不可用为false // 如:{“checkResult”:{“chooseImage”:true},“errMsg”:“checkJsApi:ok”} } }); // 通过ready接口处理成功验证 wx.ready(function() { const share = { title: mainTitle, // 分享出去的title desc: subTitle, // 描述信息 imgUrl: smallIcons, // 分享的小图标 link: url, // 分享的除去的url success: function() { dosometing(); // 分享成功,成功之后要做的事情 }, cancel: function() { dosometing(); // 分享取消,取消之后要做的事情 } }; wx.onMenuShareAppMessage(share); // 微信好友 wx.onMenuShareTimeline(share); // 朋友圈 wx.onMenuShareQQ(share); // QQ wx.onMenuShareQZone(share); // QQ空间 wx.onMenuShareWeibo(share); // 腾讯微博 }); // 如果失败 , 获取失败信息 wx.error(function(res) { console.log(“错误”, res); });3.假想的坑我看别人的分享,点击分享都是有如上一个引导图的(以为是官网自带的),但是我做好没有引导图,我开始一只以为我那一步出问题了,后来我发现,这个图是要自己加的,点击分享,打开这个蒙层,在成功回调里面,把这个蒙层去掉。????blog:https://hericium.github.io/20… ...

January 21, 2019 · 1 min · jiezi

微信支付分开通攻略!

近期,许多朋友秀出了微信支付分,是啥?想必大家都知道,类似于蚂蚁信用分。现已在北上微信支付分开通攻略!上线,具体已上线城市不明确,预计在2019年内会在全国全部覆盖。微信支付分没有入口,如何开通?接下来是重点开通前注意:1️ 不是所有人都能开通(如果开通不了,可能你所在城市还没上线)2️ 请先看完看清开通步骤再操作,避免误操作造成经济损失!(我可不负责哦)开通步骤如下第一步 长按扫码第二步扫码可能人数较多,需要排队倒计时3分钟结束后,点击重新租借(若无需排队,跳过这一步)[图片上传中…(image-45a51c-1547255237857-8)]第三步 确认开通,并申请权益第四步 开通成功,并退出切记:请退出,退出,退出租了,你可还不了,我可不赔哦!第五步 点进钱包里,就可看到支付分入口微信支付分达到550,可以免押金使用充电宝,一些酒店也可以免押入住。据说最高分有822,快查一下你有多少分吧!快过年了,推荐两个红包活动大家可以参与一下,买点好吃的!京东无门槛红包,这个强力推荐,无门槛可叠加!邀请越多人打开,可得更多,每隔5个为大包! 云闪付红包,可线上购物或线下便利店使用!如果觉得不错!请给个「好看」并分享给你的朋友! THANDKSEnd -一个立志成大腿而每天努力奋斗的年轻人伴学习伴成长,成长之路你并不孤单!

January 12, 2019 · 1 min · jiezi

个税计算器 / 微信小程序开发

2019年1月1日即将到来,码农们除了关心自己的技能之外,还有薪资是不是可以多拿点。 每次算的时候 都要百度一下个人所得税,但是很多都是老的税率计算,找一个新的出来还是比较麻烦,所以个人开发了一个最新税率的小程序。解决和我有着一样痛苦的码农们的问题。根据最新税改后计算个人所得税的计算器。目前支持南京,后续开放 杭州 上海 北京等城市。 如果有疑问的可以加最下方 开发者微信。首先在微信官网下载微信小程序开发工具 https://mp.weixin.qq.com在https://mp.weixin.qq.com 注册小程序账号,完成个人实名认证。在小程序后台拿到appid,下面就可以开发了。实例查看二维码:先使用weui 小程序ui框架就行页面布局<button block type=“dark” bindtap=‘calculationBindtap’>计算</button>其次写JS代码(计算按钮逻辑代码)import data from ‘./data’const app = getApp;Page({ data: { options1: data, value: ‘1’, checked: true, standard: 1, marking: 5000, beforetaxCount: 0, specialitemCount: 0 }, calculationBindtap:function(){ // 开始计算 计算完成把计算结果放在result对象中 var beforetaxCount = this.data.beforetaxCount; var specialitemCount = this.data.specialitemCount; var marking = this.data.marking; if (beforetaxCount == null || beforetaxCount == 0 || beforetaxCount == ‘’){ wx.showToast({ title: ‘输入正确薪资’, mask: true, icon: ’loading’ }) return; } if (specialitemCount == null || specialitemCount == ‘’){ specialitemCount = 0; } // 开始计算 var oldNum = 0.08; var medNum = 0.02; var unemNum = 0.005; var workNum = 0; var giveNum = 0; var providentfundNum = 0.08; var insuranceBase = 19935; var providentfundBase = 25300; var oldcount = 0; var medcount = 0; var unemcount = 0; var workcount = 0; var givecount = 0; var providentfundcount = 0; var privateFee = 0; var plusFee = 0; if(this.data.checked){ if (parseFloat(beforetaxCount) > parseFloat(insuranceBase)) { oldcount = parseFloat(insuranceBase) * parseFloat(oldNum); medcount = parseFloat(insuranceBase) * parseFloat(medNum); unemcount = parseFloat(insuranceBase) * parseFloat(unemNum); workcount = parseFloat(insuranceBase) * parseFloat(workNum); givecount = parseFloat(insuranceBase) * parseFloat(giveNum); } else { oldcount = parseFloat(beforetaxCount) * parseFloat(oldNum); medcount = parseFloat(beforetaxCount) * parseFloat(medNum); unemcount = parseFloat(beforetaxCount) * parseFloat(unemNum); workcount = parseFloat(beforetaxCount) * parseFloat(workNum); givecount = parseFloat(beforetaxCount) * parseFloat(giveNum); } if (parseFloat(beforetaxCount) > parseFloat(providentfundBase)) { providentfundcount = parseFloat(providentfundBase) * parseFloat(providentfundNum); } else { providentfundcount = parseFloat(beforetaxCount) * parseFloat(providentfundNum); } } // 保险总费用 var totalInsuranceFee = parseFloat(oldcount) + parseFloat(medcount) + parseFloat(unemcount) + parseFloat(workcount) + parseFloat(givecount); // 公积金费用 var totalProvidentfundFee = providentfundcount; // 下面的钱 交税 console.log(this.data.marking); var otherFee = parseFloat(beforetaxCount) - parseFloat(totalInsuranceFee) - parseFloat(totalProvidentfundFee) - parseFloat(this.data.marking) - parseFloat(specialitemCount); if (parseFloat(otherFee) <= 3000 && parseFloat(otherFee) > 0) { privateFee = parseFloat(otherFee) * 0.03; plusFee = 0; } if (parseFloat(otherFee) <= 12000 && parseFloat(otherFee) > 3000) { privateFee = parseFloat(otherFee) * 0.1; plusFee = 210; } if (parseFloat(otherFee) <= 25000 && parseFloat(otherFee) > 12000) { privateFee = parseFloat(otherFee) * 0.2; plusFee = 1410; } if (parseFloat(otherFee) <= 35000 && parseFloat(otherFee) > 25000) { privateFee = parseFloat(otherFee) * 0.25; plusFee = 2660; } if (parseFloat(otherFee) <= 55000 && parseFloat(otherFee) > 35000) { privateFee = parseFloat(otherFee) * 0.3; plusFee = 4410; } if (parseFloat(otherFee) <= 80000 && parseFloat(otherFee) > 55000) { privateFee = parseFloat(otherFee) * 0.35; plusFee = 7160; } if ( parseFloat(otherFee) > 80000) { privateFee = parseFloat(otherFee) * 0.45; plusFee = 15160; } var result = {}; result.insuranceCount = totalInsuranceFee; result.providentfundCount = totalProvidentfundFee; result.providentfundNum = parseFloat(providentfundNum) * 100; result.money = parseFloat(beforetaxCount) - parseFloat(totalInsuranceFee) - parseFloat(totalProvidentfundFee) - parseFloat(privateFee) + parseFloat(plusFee); result.privateFee = privateFee - parseFloat(plusFee); result.specialitemCount = specialitemCount; result.oldNum = parseFloat(oldNum) * 100; result.medNum = parseFloat(medNum) * 100; result.unemNum = parseFloat(unemNum) * 100; result.workNum = parseFloat(workNum) * 100; result.giveNum = parseFloat(giveNum) * 100; result.oldcount = parseFloat(oldcount); result.medcount = parseFloat(medcount); result.unemcount = parseFloat(unemcount); result.workcount = parseFloat(workcount); result.givecount = parseFloat(givecount); wx.setStorage({ key: ‘result’, data: result, success:function(){ wx.navigateTo({ url: ‘../calculation/calculationResult’, }) } }) },})把计算好的结果放在result对象中 通过wx.setStorage 放在缓存中,传到下一个页面。最后展示出来。 ...

December 29, 2018 · 3 min · jiezi

1个开发如何撑起一个过亿用户的小程序

本文由云+社区发表2018年12月,腾讯相册累计用户量突破1亿,月活1200万,阿拉丁指数排行 Top 30,已经成为小程序生态的重量级玩家。三个多月来,腾讯相册围绕【在微信分享相册照片】这一核心场景,快速优化和新增一系列社交化功能,配合适当的运营,实现累计用户量突破1亿,大大超过预期。可是,谁曾想到,这样一个亿级体量的小程序,竟然是一个开发做出来的?他又是有哪般“绝技”,可以一个人撑起一个用户过亿的小程序?后台人力紧缺,怎么办?当我第一次见到腾讯相册小程序的开发David(化名)时,他显得忧心忡忡。“年底的目标是要过千万的用户,但现在只有几位前端和后台开发。不仅如此,我们的后台开发还不是百分百能够投入到这个项目,大部分时间要抽身支援其它项目,人力非常紧缺。此外,原有后台系统有不少历史包袱,在原有架构上做新的社交化功能开发是不现实的。怎么办?“要不试试’小程序·云开发’吧,只需要前端就可以把小程序搞起,正好解决我们缺后台的难题。”于是,David作为腾讯相册前端开发团队的骨干,担当起用小程序·云开发实现腾讯相册小程序社交化功能的重任。“第一次接触到’小程序·云开发‘时,觉得这个东西(小程序·云开发)理念挺新颖的———小程序无服务开发模式。在一般的小程序开发中,有三大功能小程序开无法绕开后台的帮助,它门分别是数据读取、文件管理以及敏感逻辑的处理(如权限)。因此,传统的开发模式,在小程序端都必须发送请求到后台进行鉴权,并且处理相关的文件或者数据。即使使用 Node 来搭建后端服务,也需要耗费不少的搭基础架构、后期运维的工作量。”“而小程序·云开发则释放了小程序开发者的手脚,赋予了开发者安全、稳定读取数据、上传文件和控制权限的能力,其它的负载、容灾、监控等,我们小程序开发者只需要关注业务逻辑,专注写好业务逻辑即可,其他的事情完全可以不用操心了!本来我还一筹莫展,了解完’小程序·云开发‘的产品原理以后,我瞬间心里有谱了。”二维码扫不出来了道路总是不平坦的 ,在腾讯相册小程序通往用户破亿的道路上,困难重重。由于腾讯相册的二维码需要带上的信息量过大,因此它的二维码显得密密麻麻。这种密集的二维码在某些Android机型下,容易出现无法识别小程序的问题。这严重制约了腾讯相册小程序分享获客的能力。(需要存储name, ownerid, page等大量信息)这个事情的解决并不难,只需后台开发把数据先存储到数据库中,然后把数据id放到分享链接上,这样,链接便可以转化成32个字符的短链接,让二维码看起来没有那么密集了。但由于后台人力不足,于是前端开发David利用小程序· 云开发的数据库存储能力,通过调用db.collection(‘qr’).add接口,快速实现数据在数据库中的存储。(云开发数据库,格式类似MongoDB)(云开发数据库索引,可加快数据读取)此外,腾讯相册还借住小程序·云开发的云函数能力,生成辨识度更高的小程序码(小程序码文档),用以在朋友圈里传播分享。(生成小程序码的云函数逻辑)(优化后的分享图片和小程序码)2天上线评论点赞功能(评论与点赞功能)腾讯相册在微信端的核心应用场景是“在微信做分享相册照片”,为了增强腾讯相册用户在微信里的互动,提升用户粘性和留存,腾讯相册决定新增评论与点赞功能,并且把聊天评论就直接在微信聊天窗口里面实现。在这里,腾讯相册的David面临了两个选择,一是按原开发模式(前台开发-后台开发-前后台联调)做这个功能,面临的问题便是开发周期长、缺后台、迭代速度慢;另一个就是借助云开发的能力,撸起袖子自己上。为了加快产品迭代速度,David决定采取云开发的开发方式。评论、点赞通过云开发的数据库插入和查询接口,如db.collection(‘comment’).add,很快就实现了。但遇到棘手的问题是,对于一些敏感的操作比如删除和编辑评论、点赞这些敏感操作,还需要到用户的鉴权操作,而这些鉴权信息,都在原有的后台。此时,云函数的路由功能便发挥出作用了。(评论点赞逻辑)用户进行评论点赞的时候,会在小程序端发起请求调用云函数并带上 openid,云函数用 openid 查询原有的后台服务看看该用户是否有权限进行操作,如果用户具有权限,则把评论和点赞的数据都写入云开发的数据库中。就这样,借住小程序·云开发的能力,腾讯相册仅用2天时间,完成了在传统开发模式下需要1周多工作量的开发工作。 原有开发模式云开发全栈开发工作量后台1周(微信登录态校验+业务逻辑server开发)+ 前后台联调1天1 - 2天,无需联调此文已由作者授权腾讯云+社区发布*s

December 19, 2018 · 1 min · jiezi

小程序登录、微信网页授权(Java版)

小程序登录、微信网页授权(Java版)首先呢,“登录”、“授权”、“授权登录”,是一样的意思,不用纠结。写小程序授权登录的代码前,需要了解清楚openid与unionid的区别,这里再简单介绍一下:腾讯有个 “微信·开放平台”,只有企业才能注册账号,可理解为微信体系里,最顶级的账号。官网地址:https://open.weixin.qq.com除了这个微信开放平台,还有另一个叫做 “微信公众平台”,可注册四种账号,包括服务号、订阅号、小程序、企业微信。也就是说,公众号(服务号和订阅号可统称为公众号)占一个账号,小程序也占一个账号。在没有绑定开放平台前,小程序授权登录只能拿到用户的openid。官网地址:https://mp.weixin.qq.com小程序可绑定在公众号下,公众号可以绑定在微信开放平台下,小程序也可以绑定在微信开放平台下。(好像有点小绕)简单点说,所有的公众平台账号都需要绑定在 “开放平台” 下,才可获得的unionid,这是打通同个企业下所有微信公众账号的最有效方法(官方推荐)更加具体的可自行百度…一、以下为小程序登录的代码:方式一:通过code调用code2session接口获得message,包含openid、session_key,满足条件的情况下还能直接获得unionid条件如下:(存在局限性)官方说明UnionID获取途径,如果开发者帐号下存在同主体的公众号,并且该用户已经关注了该公众号。开发者可以直接通过 wx.login + code2Session 获取到该用户 UnionID,无须用户再次授权。开发者帐号下存在同主体的公众号或移动应用,并且该用户已经授权登录过该公众号或移动应用。也可通过code2session获取该用户的 UnionID。/** * Author: huanglp * Date: 2018-11-28 /public class WeiXinUtils { private static Logger log = LoggerFactory.getLogger(WeiXinUtils.class); /* * 通过前端传过来的code, 调用小程序登录接口, 获取到message并返回 (包含openid session_key等) * * @param code * @return / public static JSONObject login(String code) { log.info("==============小程序登录方法开始================"); WxMiniProperties properties = WeiXinPropertiesUtils.getWxMiniProperties(); String url = properties.getInterfaceUrl() + “/sns/jscode2session?appid=” + properties.getAppId() + “&secret=” + properties.getAppSecret() + “&js_code=” + code + “&grant_type=authorization_code”; JSONObject message; try { // RestTemplate是Spring封装好的, 挺好用, 可做成单例模式 RestTemplate restTemplate = new RestTemplate(); String response = restTemplate.getForObject(url, String.class); message = JSON.parseObject(response); } catch (Exception e) { log.error(“微信服务器请求错误”, e); message = new JSONObject(); } log.info(“message:” + message.toString()); log.info("==============小程序登录方法结束================"); return message; // 后续, 可获取openid session_key等数据, 以下代码一般放在Service层 //if (message.get(“errcode”) != null) { // throw new ValidationException(message.toString()); //} //String openid = message.get(“openid”).toString(); //String sessionKey = message.get(“session_key”).toString(); //… }}补充1: WeiXinPropertiesUtils工具类public class WeiXinPropertiesUtils { // 微信小程序配置 private static WxMiniProperties miniProperties; // 微信公众号配置 private static WxProperties wxProperties; private static void init() { if (miniProperties == null) { miniProperties = ContextLoader.getCurrentWebApplicationContext() .getBean(WxMiniProperties.class); } if (wxProperties == null) { wxProperties = ContextLoader.getCurrentWebApplicationContext() .getBean(WxProperties.class); } } public static WxMiniProperties getWxMiniProperties() { init(); return miniProperties; } public static WxProperties getWxProperties() { init(); return wxProperties; }}补充2: WxMiniProperties配置类@Data@Component@ConfigurationProperties(prefix = “luwei.module.wx-mini”)public class WxMiniProperties { private String appId; private String appSecret; private String interfaceUrl;}到此已能通过code获取到用户的openid和session_key,但若不满足条件,即使将小程序绑定到微信开放平台上,也获取不到unionid,所以此方式不稳定,推荐使用解密的方式获取数据。方式二:通过解密的方式获取用户unionid/* * 通过encryptedData,sessionKey,iv获得解密信息, 拥有用户丰富的信息, 包含openid,unionid,昵称等 /public static JSONObject decryptWxData(String encryptedData, String sessionKey, String iv) throws Exception { log.info("============小程序登录解析数据方法开始=========="); String result = AesCbcUtil.decrypt(encryptedData, sessionKey, iv, “UTF-8”); JSONObject userInfo = new JSONObject(); if (null != result && result.length() > 0) { userInfo = JSONObject.parseObject(result); } log.info(“result: " + userInfo); log.info("============小程序登录解析数据方法结束==========”); return userInfo;}补充1: AesCbcUtil工具类,直接复制即可,需要添加bouncycastle依赖。BouncyCastle是一个开源的加解密解决方案,官网可查看http://www.bouncycastle.org/package com.luwei.common.utils;import org.bouncycastle.jce.provider.BouncyCastleProvider;import org.apache.commons.codec.binary.Base64;import javax.crypto.Cipher;import javax.crypto.spec.IvParameterSpec;import javax.crypto.spec.SecretKeySpec;import java.security.AlgorithmParameters;import java.security.Security;/* * Updated by huanglp * Date: 2018-11-28 /public class AesCbcUtil { static { Security.addProvider(new BouncyCastleProvider()); } /* * AES解密 * * @param data //被加密的数据 * @param key //加密秘钥 * @param iv //偏移量 * @param encoding //解密后的结果需要进行的编码 */ public static String decrypt(String data, String key, String iv, String encoding) { // org.apache.commons.codec.binary.Base64 byte[] dataByte = Base64.decodeBase64(data); byte[] keyByte = Base64.decodeBase64(key); byte[] ivByte = Base64.decodeBase64(iv); try { Cipher cipher = Cipher.getInstance(“AES/CBC/PKCS7Padding”); SecretKeySpec spec = new SecretKeySpec(keyByte, “AES”); AlgorithmParameters parameters = AlgorithmParameters.getInstance(“AES”); parameters.init(new IvParameterSpec(ivByte)); cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化 byte[] resultByte = cipher.doFinal(dataByte); if (null != resultByte && resultByte.length > 0) { return new String(resultByte, encoding); } return null; } catch (Exception e) { e.printStackTrace(); } return null; }}到此已经获取到 JSONObject类型的 userInfo,包含openid,unionid,昵称,头像等数据后续可以将用户信息保存到数据库,再返回给前端一个token即可,shiro经过公司封装了一层,代码如下:…// 获得用户IDint userId = wxUser.getWxUserId();shiroTokenService.afterLogout(userId);String uuid = UUID.randomUUID().toString();String token = StringUtils.deleteAny(uuid, “-”) + Long.toString(System.currentTimeMillis(), Character.MAX_RADIX);shiroTokenService.afterLogin(userId, token, null);return token;二、以下为公众号(网页)授权的代码:网页授权更加简单,可查看 官方文档需添加 riversoft 相关依赖包,公众号网页授权,只需要将公众号绑定了开放平台,就能获取到unionid及其他用户信息。public static OpenUser webSiteLogin(String code, String state) { log.info("============微信公众号(网页)授权开始==========="); WxProperties properties = WeiXinPropertiesUtils.getWxProperties(); AppSetting appSetting = new AppSetting(properties.getAppId(), properties.getAppSecret()); OpenOAuth2s openOAuth2s = OpenOAuth2s.with(appSetting); AccessToken accessToken = openOAuth2s.getAccessToken(code); // 获取用户信息 OpenUser openUser = openOAuth2s.userInfo(accessToken.getAccessToken(), accessToken.getOpenId()); log.info("============微信公众号(网页)授权结束==========="); return openUser; // 后续, 可将用户信息保存 // 最后一步, 生成token后, 需重定向回页面 //return “redirect:” + state + “?token=” + token;}署名 广州芦苇科技Java开发团队芦苇科技-广州专业互联网软件服务公司抓住每一处细节 ,创造每一个美好关注我们的公众号,了解更多想和我们一起奋斗吗?lagou搜索“ 芦苇科技 ”或者投放简历到 server@talkmoney.cn 加入我们吧关注我们,你的评论和点赞对我们最大的支持 ...

December 19, 2018 · 3 min · jiezi

一张图清晰解释微信三方平台获取授权流程

背景微信公众平台体系,大家最为熟悉的,一个是公众号,另一个就是小程序。如果需要使用公众号的高级功能,那么大家首先想到的就是自组开发团队来干这些活儿。绝大多数情况下,公众号运营方会把这些工作外包出去;但是外包出去之后会有一个风险:账号的所有权总不能外包出去吧,万一有风险,我能够把外包工作收回。微信公众号体系原生支持这种 “外包” 思路,那就是微信第三方平台,公众号能够通过这套体系,将公众号的部分功能和权限开放给第三方。这在微信开放平台中可以找到相应的文档。与自有公众号开发不同,微信三方平台的授权体系是慎之又慎,笔者第一次接触的时候,被文档中提及的各种 token、各种 ticket 搞晕了,于是特意整理了这个流程,以图表的方式将授权流程说明下来,便于查阅。已经学习了授权流程的同学,可以直接将本文拉到最后面查看完整图。本文按照授权顺序,一步一步地说明。图中关键的 token 或 ticket 数据,均用彩色标出并一一对应。希望本文对微信三方平台开发者能够有所帮助。授权步骤三方平台数据准备微信三方平台也是在微信开放平台上的账号,也有 appid 的概念。在微信的文档中,三方平台称为 “component”。三方平台需要实现一个供微信回调的 URL,在平台中称为 “授权事件接收URL”(以下简称 “通知回调”),在应用详情页中进行配置。不要被这个名称误导了,其实所有和三方平台直接相关的事件都会经过这个 URL 通知。获取 component_access_token这里涉及流程中的两个术语:component_verify_ticket 和 component_access_token。微信会每十分钟往通知回调中发送一个消息,将参数 component_verify_ticket 告知三方平台后台。三方平台拿到这个消息后,则需要使用自己的 app_secret 和 appid 信息,加上微信推送的这个 ticket,通过微信三方平台的 api_component_token 接口,向微信平台换取 component_access_token。生成授权注册页面 URL让公众号点击授权有两种模式,一种是引导公众号所有者扫码进入一个授权页;另一种范式是在移动端点击链接来授权。两种方式对后台而言大同小异,本文讲解第一种。这里其实包含了两个小步骤:首先是三方平台后台向微信请求获得预授权码 pre_auth_code;第二步是使用这个预授权码,来组合成一个 URL 给公众号所有者扫码。关键的参数如下(componentloginpage 是用于扫码的 URL):公众号授权获取授权的公众号公众号扫码授权后,微信会向通知回调发送消息,除了告知授权的公众号(称为 “authorizer”)的 appid 之外,最重要的是推送一个新的票据字段 authorization_code,这个 code 是与授予权限的公众号绑定的:拉取公众号信息及其授予的权限这分别是两个 API,其中比较重要的是拉取公众号授予的权限范围,调用了接口 “api_query_auth”。除了获得授权范围之外,最重要的,是再引入两个新参数:authorizer_access_token:用在后文 “代公众号调用接口” 中,替代微信公众平台的 access_token 参数。authorizer_refresh_token:用于定时刷新 access_token两个 API 的调用图如下:代公众号实现业务刷新 authorizer_access_token前文提到,通过 API:api_query_auth 可以获得用于替代公众号的authorizer_access_token。有了这个之后,就可以代公众号中使用 access_token 的调用。同样地,这个 token 也有过期时间,因此三方平台需要调用 API,在 token 即将失效时刷新。使用这个 API 循环刷新即可:获取微信 JS-SDK 的 ticket微信 JS-SDK 接口使用的不是 access_token,而是被称为 jsapi_ticket的一个票据。普通的公众号使用 access_token 来换取,三方平台则使用 component_access_token 来换取:其实这个接口已经不是微信三方应用的范围了,只是普通的微信公众平台接口。但是因为非常常用,所以还是在这里说明了一下。授权流程总览<span id=‘总览’>上面所提及的各个分步骤,组合成一览图如下(图片比较宽,推荐大屏幕查看或者放大查看):<>图中各个调用过程的标题,是 API 的名称,可以作为关键字在微信文档中搜索。参考资料第三方平台概述JS-SDK使用权限签名算法,搜索 “JS-SDK使用权限签名算法”本文章采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。本文地址:https://segmentfault.com/a/1190000017402102。原文发布于:https://cloud.tencent.com/developer/article/1368038,也是本人的专栏。 ...

December 17, 2018 · 1 min · jiezi

推荐一款快速制作通讯录的微信小插件

今天,我们提交了第一版,刚刚通过微信审核的小程序插件 ——「爸妈搜通讯录」。只要有通讯录的地方,就会需要对通讯录姓名进行分组排序和界面设计,主流做法基本是按照人名的拼音首字母排序,效果图如下:现在让我开始说一说怎么使用我们刚新鲜出炉的小程序插件。一句话介绍简便、快速的生成通讯录的小插件。使用方法1、 在微信小程序管理后台——设置——第三方服务,按 AppID(wxea14f39af1d4d74a)搜索到该插件并申请授权(ps:一般不会出现拒绝的情况。如果申请被拒绝了,请重新申请,有时候管理员手抽点错了,请见谅! 有任何好的建议可以通过微信、邮箱、手机号联系!)。 2、在要使用该插件的小程序 app.json 文件中引入插件声明。“plugins”: { “BmsDirectory”: { “version”: “1.0.0”, “provider”: “wxea14f39af1d4d74a” }}3、在需要使用到该插件的小程序页面的 JSON 配置文件中,做以下配置:{ “usingComponents”: { “BmsDirectory”: “plugin://BmsDirectory/BmsDirectory” }}4、在相应的 HTML 页面中添加以下语句即可完成插件的嵌入。<BmsDirectory />属性属性名类型默认值说明 userList Array"[]“通讯录数据 userList 的属性属性名类型默认值说明nameString’‘名字信息telString’‘电话信息 avatarurl String有默认头像头像信息 <BmsDirectory userList=”{{userList}}" headportrait=‘headportrait’ />data:{ userList: [ { name: ‘咖啡’, tel: ‘12345678900’, avatarurl:’’ }, { name: ‘小咖啡’, tel: ‘12345678900’ }, { name: ‘小小咖啡’, tel: ‘12345678900’ }, { name: ‘c小小咖啡’, tel: ‘12345678900’ }, { name: ‘-小小咖啡’, tel: ‘12345678900’ }, { name: ‘+小小咖啡’, tel: ‘12345678900’ }, ]}样式属性名类型说明headportraitString头像的样式phonestyleString电话号码信息的演示 namestyle String名字信息的样式 titlestyle String名字上方分类小标题的样式 msgstyle String每一条信息的整体样式/* 头像 /.headportrait{ / width: 100rpx !important; height: 100rpx !important; /}/ 手机号 /.phonestyle{ font-size: 26rpx !important;}/ 名字 /.namestyle{ font-size: 28rpx !important;}/ 首字母标题 /.titlestyle{ font-size: 28rpx !important; / color: red !important; /}/ 每个信息的样式 /.msgstyle{ / padding: 50rpx 20rpx !important; */} 事件属性名类型说明 bindgetcall String 点击每条信息时触发的事件 <BmsDirectory userList=’{{userList}}’ bindgetcall=‘getcall’/> 效果总结这是我们团队做的第「五」个微信小插件,每个插件制作的标准就是,把复杂的逻辑交给我们来做。使用者只要简单的引入,用最便捷的输入参数,以达到最好的效果。欢迎微信小程序开发者使用我们的其它插件:爸妈搜日历提供简约不简单的日历基本功能,自定义样式,考勤状态等功能。插件地址:https://mp.weixin.qq.com/wxopen/pluginbasicprofile?action=intro&appid=wx23a9cef3522e4f7c爸妈搜富文本小程序富文本处理 rich-text, 将无法识别的标签改为可识别的, 适配移动设备。插件地址:https://mp.weixin.qq.com/wxopen/pluginbasicprofile?action=intro&appid=wx54e7e5b0ebeda242爸妈搜海报 Maker插件地址:https://mp.weixin.qq.com/wxopen/pluginbasicprofile?action=intro&appid=wxbf07f0f22c6c200d爸妈搜表单圈插件地址:https://mp.weixin.qq.com/wxopen/pluginbasicprofile?action=intro&appid=wx6aaef9edf974a564最后,放出我们团队插件开发者的联系方式,有什么问题都可以联系她哦~ ...

November 29, 2018 · 1 min · jiezi

自定义微信分享样式

博客地址Preface产品希望我们在微信分享出去的链接,有自己的样式,而不是仅仅一个链接。用产品的话来说,你发给客户一个链接,客户敢点么???听着比较有意思,不过也不能说完全没有道理,毕竟各种各样的诈骗大家也是有所耳闻,经确认,产品想要:而我们当前分享是:Main总监给我提示说,微信有 js-sdk ,可以在 js 里设置这个样式。于是,我找到了微信 JS-SDK 说明文档,基本上就是根据文档走些配置,这个要和产品那边要些账号密码,改些东西之类,根据文档来,没什么好说的。大体流程如下:步骤一:绑定域名步骤二:引入 JS 文件步骤三:通过 config 接口注入权限验证配置wx.config({}) //传入一些初始化参数步骤四:通过 ready 接口处理成功验证wx.ready(function() {}) //传入成功回调步骤五:通过 error 接口处理失败验证wx.error(function() {}) //传入失败回调实际操作的时候,遇到了几点麻烦,这里需要提一下:测试的时候,注意开启 debug 模式,方便定位问题。wx.config({ debug: true /其他参数/ })出于安全考虑,开发者必须在服务器端实现签名的逻辑。这个是文档说的,反正就是给后台处理了,最终前端初始化需要的几个字段,除了 debug 和 jsApiList ,都是从后台拿的。wx.config({ debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId: ‘’, // 必填,公众号的唯一标识 timestamp: , // 必填,生成签名的时间戳 nonceStr: ‘’, // 必填,生成签名的随机串 signature: ‘’,// 必填,签名 jsApiList: [] // 必填,需要使用的JS接口列表});后台在实现的时候,可能需要注意文档提示的两点:access_token(有效期 7200 秒,开发者必须在自己的服务全局缓存 access_token)jsapi_ticket(有效期 7200 秒,开发者必须在自己的服务全局缓存 jsapi_ticket)因为这会导致一开始生成的签名没错,但是两个小时后就失效了。代码逻辑通常的逻辑都是前端从后台拿到上面的几个字段,在前端完成初始化,然后添加初始化成功和失败的回调。示例:var link = location.href$.ajax({ url: ‘your_url’, //后台给你提供的接口 type: ‘GET’, data: { url: link }, async: true, dataType: ‘json’, success: function(data) { wx.config({ debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来 appId: data.configMap.appId, // 必填,公众号的唯一标识 timestamp: data.configMap.timestamp, // 必填,生成签名的时间戳 nonceStr: data.configMap.nonceStr, // 必填,生成签名的随机串 signature: data.configMap.signature, // 必填,签名,见附录1 jsApiList: [‘onMenuShareTimeline’, ‘onMenuShareAppMessage’] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 }) wx.ready(function(res) { wx.onMenuShareAppMessage({ title: document.title, desc: document.title, link: link, imgUrl: Imgurl, trigger: function(res) {}, success: function(res) {}, cancel: function(res) {}, fail: function(res) {} }) wx.onMenuShareTimeline({ title: document.title, link: link, imgUrl: Imgurl, trigger: function(res) {}, success: function(res) {}, cancel: function(res) {}, fail: function(res) {} }) }) wx.error(function(res) { alert(res) }) }, error: function(error) { alert(error) }})我司稍微特殊些,直接把初始化的代码放在前面需要引入微信的 js 文件后面了,所以我直接引入这个文件就完成了初始化操作。不过,我还是需要在引入后监听初始化成功和失败的回调。我司代码:<script src="./js/shareInWeChat.js?debug=1"></script><!– 里面包含了 wx.config({}) 的代码–><!– 通过 debug 参数来切换调试模式 –>setWeChatShareStyle(product, imgUrl)function setWeChatShareStyle(product, imgUrl) { var success = function(res) {} var fail = function(res) {} var desc = product.description && product.description !== ’’ ? product.description : ‘后备描述’ wx.ready(function() { var eventConf = { title: product.name, desc: desc, imgUrl: imgUrl, link: window.location.href, success: success } if (pubMethods.isAndroid()) { // 安卓适用于老接口,新接口不行 wx.onMenuShareAppMessage(eventConf) wx.onMenuShareTimeline(eventConf) wx.onMenuShareQQ(eventConf) wx.onMenuShareQZone(eventConf) } if (pubMethods.isIOS()) { // iOS 适用于新接口,老接口不行 wx.updateAppMessageShareData(eventConf, success) wx.updateTimelineShareData(eventConf, success) } }) wx.error(fail)}最初我担心,这样可能会监听不到 wx.config 初始化的结果,结果发现还是可以监听到的,说明 wx.config 里面的操作是个异步操作。代码兼容性统一传参如上面代码所示,虽然根据微信的文档,对于不同的接口,传的参数稍有区别,但是我为了方便,都放在 eventConf 里面了,事实证明也是可以的(不可以我就要吐槽了,毕竟传入的是对象)。接口更新的 bug虽然微信文档上有接口更新的说明:请注意,原有的 wx.onMenuShareTimeline、wx.onMenuShareAppMessage、wx.onMenuShareQQ、wx.onMenuShareQZone 接口,即将废弃。请尽快迁移使用客户端 6.7.2 及 JSSDK 1.4.0 以上版本支持的 wx.updateAppMessageShareData、updateTimelineShareData 接口。但我实际上测试的结果是,安卓不支持新接口,iOS 支持,但是我如果把新老接口全用上,有一端会失败,所以最终才有上面那个机型判断的结果,对于不同的机型采用了不同的接口。if (pubMethods.isAndroid()) { // 安卓适用于老接口,新接口不行 wx.onMenuShareAppMessage(eventConf) wx.onMenuShareTimeline(eventConf) wx.onMenuShareQQ(eventConf) wx.onMenuShareQZone(eventConf)}if (pubMethods.isIOS()) { // iOS 适用于新接口,老接口不行 wx.updateAppMessageShareData(eventConf, success) wx.updateTimelineShareData(eventConf, success)}分享的图片不能是 base64由于我司需要对图片进行处理再去分享,所以当我用 canvas 导出 base64 作为 imgUrl 的时候,我发现是没有效果的。EndingReference微信分享自定义样式微信分享图标设置,以及 wx.config 配置 ...

November 24, 2018 · 2 min · jiezi

微信小程序之登录态的探索

上一篇:开发微信小程序必须要知道的事登录,几乎什么项目都会用到,其重要性不言而喻,而小程序的登录却一直是为人头疼的一件事,这里我分享下我们在小程序登录上的探索通常的登录都是通过一个表单,这很正常,但如果在小程序里你也这么做那就有点不可思议了,微信的一键登录对用户体验有多好你难道不知道?不用是不是脑子有坑?最主要——你要利用微信的生态必须需要用微信的登录,以获取相关信息来和微信交互,OK,我们进入正题用户在小程序、小游戏中需要点击组件后,才可以触发登录授权弹窗、授权自己的昵称头像等数据友情提示一下:wx.login并不需要点击组件,需要的是wx.getUserInfo,但通常我们都会用到UnionID、encryptedData、iv等信息完成完整的登录流程,本文主要聚焦的也是这种场景所以之前直接通过调用API的方式就行不通了,那么问题来了——这个点击按钮要放到哪里?放到首页,一进小程序就必须先登录。这样显然很粗暴,而且问题并没有解决,反而会把用户直接拒之门外,毕竟你不是用小程序做后台系统,什么场景都需要授权,先授权也是必须的在需要授权的时候跳到登陆页面。这样就解决了上面遇到的不需要授权的时候也被强制授权,可是这样好吗?体验上不好,操作被打断,尤其整个页面都不需要授权只有在一个地方需要授权的,例如:你正在读一篇文章,读罢深有感触,想评论一番,洋洋洒洒几十字写完正准备点击呢,他妈的跳转了!跳转了!又一个漏斗,增加用户流失率。还TM要登录!很多用户心里一定这么想那就直接放在需要登录的页面上(这不是漏斗吗?很多读者一定这么想。但想想看上面那个场景,点评论时只是需要点击下弹出的登录按钮,而且还假模假样的以微信的口吻提醒你需要登录,那你会不会登录?最起码你很愿意登录,而且来的很突然,我控几不住自己的手就点了!点了!) 可是这种方式有一个问题怎么在需要的页面都能弹出登录按钮应该很多人都能想到:抽离出组件,那怎么保证在需要的页面都有这个组件呢?错杀一千也不能放过一个!把登录组件集成到共用的父组件,然后在每个页面都使用。我也建议这么做,因为这个共用的父组件其实又很多用处,例如iPhoneX适配等 等等,什么都准备好了,什么时候需要登录呢?XX,这个肯定是你自己控制的啦。嗯~好吧,我们来理一理在哪里校验是否需要鉴权请求接口的时候,嗯~这是大家的共识BOSS来了怎么鉴权官方的这张图已经做了很详尽的说明,这里不做赘述 但是看到session_key了吗?看到官方同时说的了吗所以问题又来了怎么保证session_key的有效性诚如上图要保证调用接口时后端session_key不失效,只能在每次调用前先使用wx.checkSession检查是否有效实践中也发现wx.checkSeesion非常耗时,大约200ms,所以也不能每次接口调用前都使用wx.checkSession检查是否有效同时要注意⚠️前端不能随便重新执行wx.login,因为可能导致正在进行的其它后端任务session_key失效天啦噜,怎么办?! 通过实践和偶然的发现——官方的示例代码 得知:在使用小程序期间session_key是不会失效的,so,你想到了什么?在每个请求前去校验有效性将校验有效性的结果存储起来通过async/await和刚才存储起来的结果来保证不过多调用wx.checkSession先问个问题:你准备用什么方式来存储校验的结果?。。。让思考先飞一会。。。。。。。。。。。。。。。。。。。。。。。。。。。storage吗?当然可以,不过不够完美,为什么?因为storage是永久的存储,而session_key的有效期却只是在使用小程序期间,所以你需要在小程序结束后手动重置该状态以重新校验其有效性,那是不是在app的onUnload里重置呢?不是!开发过小程序的应该都知道,那就是结束使用小程序的方式太多,不能保证每种方式都会触发onUnload,例如用户直接销毁了微信进程????(其实你也可以在app的onShow里搞)那用什么呢?直接用内存啊,借助内存的自动管理来智能管理,所以最终代码应该是这样的// doRequest.jslet wxSessionValid = null // 微信session_key的有效性// 带鉴权的请求封装async function doRequestWithCheckAuth() { … if (typeof wxSessionValid !== ‘boolean’) { wxSessionValid = await checkWxSession() // 检查微信session是否有效 } if (!wxSessionValid) { await reLogin() // 重新登录 } wxSessionValid = true // 重新登陆后session_key一定有效 …}这样是不是看起来比较完美了?嗯~不知道有没有同学着急问业务侧的session(自定义的登录态)怎么没讲?嗯,那现在讲吧怎么校验完整的认证体系其实很简单,都不想把它作为一部分来讲,但既然讲了就必然有我想强调的校验微信端的session_key略有麻烦,但不应该把它抛给服务端服务端不能直接校验session_key的有效性而是通过调用接口发现错误了才知道失效了,这是被动的服务端需要同时维护两个session而放在前端我们只需要校验两个session的有效性即可,任何一个失效就重新登录,这是积极主动有效的操作,应该被提倡贯通OK,基本上梳理的差不多了,就差弹登录按钮了,这个简单,调用刚才封装的组件的方法就行了嘛,bingo,可是,点完允许后呢?怎么继续用户的操作呢?怎么能让用户的体验不被打断呢?先回放下刚才reLogin的代码async function reLogin() { // 确保有用户信息 await new Promise(resolve => { // ⚠️注意开头有await!!! wx.getSetting({ success: (res) => { // 如果用户没有授权或者没有必要的用户信息 if (!res.authSetting[‘scope.userInfo’] || !_.isRealTrue(wx.getStorageSync(‘userInfoRes’).userInfo)) { navToLogin(resolve) // 去提示用户点击登录按钮,⚠️注意:并把当前的resolve带过去 } else { resolve() // 静默登录 } } }) }) return new Promise((resolve) => { wx.login({ success: res => { login(res.code).then((jwt) => { resolve(jwt) // resolve jwt }) // 通过code进行登录 }, fail(err) { wx.showToast({ title: err.errMsg, icon: ’none’, duration: 2000 }) } }) })}function navToLogin(resolve) { /* eslint-disable no-undef */ const pages = getCurrentPages() const page = pages[pages.length - 1] // 当前page page.openLoginModal(resolve) // 打开登录按钮弹框,并把当前的resolve带过去}上面的代码注释里有两个⚠️注意看到没?是的,通过回调的方式????当用户同意授权了就继续余下的逻辑,如果被拒绝了,则安利他,再拒绝就终止操作,下次需要授权也会继续弹出授权 有不明白欢迎评论留言指出,我再做说明修改完整源码以后会放出的,通过wepy搭建的一个框架 下一篇会讲api的封装谢谢 ...

November 16, 2018 · 1 min · jiezi

开发微信小程序必须要知道的事

为什么是小程序?为什么我们会开发小程序呢?或许是因为工作需要,或许是源于自己的追求(来自名利的欲望),但我要说——这是一种缘分,很美好的缘分,很多年后还值得庆幸的缘分小程序目前可以分为三个阶段一是语音和摇一摇(还有yue pao利器的传说)二是公众号,也就是这时注定了小程序的出现是历史的必然选择(shihouzhuge),为什么这么说呢?因为微信在开放了webview的同时加入了js-sdk的开发工具包,而这就是小程序的前身三就是当下的微信os,能跑小程序的微信我们继续来说说第二点,有了js-sdk不就可以了吗?不就可以打通微信了吗?还要什么小程序?!可是人家是有梦想的鹅厂啊!!?先从技术上说,js-sdk只是为传统网页提供包含微信api的开发工具包,并没有解决移动网页遇到的体验不良问题,所以小程序就做了资源离线存储,提高加载速度提供更强的开放能力通过构建组件系统实现对安全性的管控通过内置实现的组件提高开发速度和降低开发成本开放入口啊,不像网页只能通过链接打开加上其他XXX就搞出了比拟原生的体验(chadebushao)微信的梦想上说作为一个月活超10亿的超级app,人口红利已达天花板,所以现在开始打时长红利的主意,拓展微信的使用场景,拓宽微信的边界马化腾亲口说过:从消费互联网到产业互联网,随着产业互联网时代的到来,我们也在“连接产业”上寻求突破,而小程序就是连接产业互联网的“利器”(听不懂什么玩意)赚钱啊!鹅厂的梦想啊!做什么样的小程序?回到上面的引子,为什么值得庆幸?因为上面说了——能降低开发成本,能提高用户体验,能褥流量!能让每个人都有机会搞事情!!!搞什么呢?我也不知道,如果你有好的想法欢迎联系我????不过,这里分享下我的想法战线不能长!张小龙说过——“用完即走”,其实这不是原因,只是我调个书袋而已????但微信确实是这样啊,聊天、朋友圈,好像确实没什么太丧心病狂的一直拉着你不走(好像现在还有看一看?始终记住——鹅厂有梦想!)所以你做的东西要符合人家产品的思想!好吧,说个实际的场景,如果你要在小程序里的创作文章,那别人来一条信息你回不回?不回?你的思绪回不回被打乱?不会?你的心情会不会很烦?不会?????你赢了,来生再见,所以权衡好你的功能设计,战线越长越容易死短!平!快! 对应上面。就是快速进入主题,功能点一目了然,功能也尽量单一,该干什么尽快干什么!例如让用户分享,让用户pay,快!快!快!不犹豫,让用户尽快上车做矩阵,对应上面,如果你想把app的功能都搬到小程序上,那一定要做功能拆分,做多个小程序形成矩阵小程序os长什么样?想种一个小程序总先知道这片土地什么样吧?OK,欢迎来到小程序黑土地。。。首先我们先说说小程序用到的两个线程——渲染线程、脚本线程,与网页开发不同,这两个线程是分开的,分别运行在不同的线程中,而网页则是互斥的,也就是说视图和脚本被分开了,在不同的线程里,这就导致了和普通网页开发一个很大的不同——没有DOM API,而且也不是运行在浏览器里所以也没有BOM API我们再看图还发现小程序总共有三种运行环境,并且!每个环境两个线程还都不一样!所以同学们啊,在开发工具上行的在真机上不一定行啊!可别太天真了,一定要在真机上验证功能的可行性!我们有没有想过小程序为什么要费那么大功夫重造轮子?不直接用成熟的web技术?说是体验,其实我觉得最主要的是微信想管控一切,不是你想怎样就可以怎样,而是我让你怎样,你才能怎样(至今我还对此很不爽)所以就干掉了灵活的web,别被我带沟里——小程序并不是完全没有了web,实际上你看到的就是web,只是没有暴露出来,而是微信直接通过编译小程序来替你操作了既然是两个线程,那必然要通信啊,要协作完成任务,那怎么实现的呢?看下面的通信模型 没看到图也能先想到是这个样式????,这里提示几点上图中的Native是指微信客户端逻辑层发送网络请求也经由Native转发渲染层是由多个webview组成的,为什么?为了提供更好的交互体验呀,这样也更贴近原生体验,同时避免了单个WebView的任务过于繁重,同时导致了小程序的生命周期不容易被理解(下面带你理解)通信是有时间成本的,所以在开发中我们最好使用异步接口来看下生命周期 其实了解了渲染层是由多个webview组成的就很容易理解生命周期了navigatebBack是返回上一个webview,销毁当前的webviewnavigateTo是打开承载新页面的webview,同时保留老的webviewredirectTo是在当前webview里打开新的页面左下角有两张拼一起的图是switchTab的Tabbar页面初始化之后不会被销毁!所以Tabbar页面不会unLoad,更多请参阅图片有用请点赞????下一篇文章将讲讲小程序的登录态????

November 15, 2018 · 1 min · jiezi

「腾讯地图」微信小程序插件:提供简单的路线多方案规划服务

上期,我们在《「腾讯视频」微信小程序插件介绍》一文中介绍了「腾讯视频」小程序插件的意义、使用场景以及使用方法。今天我们会与大家分享一款同样优秀的小程序插件——「腾讯地图」插件,从使用场景到使用方法,都将作出详细的介绍。「腾讯地图」插件能做什么?顾名思义,「腾讯地图」插件由腾讯地图官方出品,旨在为开发者提供简单的路线多方案规划服务,可在插件中显示指定位置间的路线方案,支持驾车、公交、步行的路线规划能力及 ETA 等基础路线信息。如果你想像「腾讯地图+」小程序一样实现地图的基础功能,使用「腾讯地图」插件是你的最佳选择。「腾讯地图+」小程序截图作为首批推出的小程序插件,「腾讯地图」插件经过了多个版本的优化,从最初的显示目标位置信息以及提供附近地图功能,到现在已经支持路线规划等能力,地图的功能几乎已经全部配备齐全。「腾讯地图」插件的使用场景场景一:收到小程序的婚礼请柬,但是请柬上的地址找不到?怎么办?如果你开发的是请柬邀请类的小程序,就会遇到上述场景。在传统开发模式中,引入完整的地图选点、路线规划组件,开发成本非常高,更多开发者选择让用户直接输入文字地址进行展示,以此作为降低开发成本的妥协方案。这样的设计不可点击,更没有路线规划的能力,用户还需手动输入去查询地址和交通路线。传统请柬 不可交互但如果开发者选择使用腾讯地图提供的同名小程序插件,开发成本将大幅降低,用户体验也能直线上升。我们在这里以婚庆请柬小程序为例进行说明:用户在编辑请柬小程序的过程中,提前设置好婚礼举办地点;当婚礼宾客收到请柬,点击地点,「腾讯地图」插件就能根据其宾客当前位置和目的地坐标,自动生成精准的导航路线。一键导航 简洁明了场景二:会议服务小帮手——提前了解参会路线与会者应该如何从高铁站、机场、火车站前往会议地点,一直都是各类会议邀请的必备内容。但长期以来,此类信息都习惯以纯文字形式进行发布,体验上存在不便理解、记忆难的问题。如果小程序能够使用「腾讯地图」插件,这类场景的体验将发生质的改变:会议组织方在小程序中提前设置多组起终点(如:机场 - 会议中心、高铁站 - 会议中心),与会者收到会议邀请后点击指定线路,就能在地图插件中查看到精确的参会路线。这样是不是比枯燥的文字多了几分智能呢?如何接入「腾讯地图」插件?「腾讯地图」的功能强大,使用起来却十分简单:1.申请使用插件。在「小程序管理后台 - 设置 - 第三方服务 - 插件管理」中查找插件名称「腾讯地图」(目前最新版本:1.0.6,appid:wx5bc2ac602a747594),并申请使用。2.引入插件代码后修改配置文件 JSON:{ “usingComponents”: { “map-route”: “plugin://myPlugin/mapRoute” }}3.使用地图插件。在相应的 WXML 文件中添加以下标签:<map-route route-info="{{routeInfo}}"></map-route>4.最后,按需求在 JS 文件中处理传入插件数据,数据包括:起点,终点经纬度及名称,路线算路方式,封装在 routeInfo 结构中:let plugin = requirePlugin(“myPlugin”)let routeInfo = { startLat: 39.90469, // 起点纬度 选填 startLng: 116.40717, // 起点经度 选填 startName: “我的位置”, // 起点名称 选填 endLat: 39.94055, // 终点纬度必传 endLng :116.43207, // 终点经度 必传 endName:“来福士购物中心”, // 终点名称 必传 mode:“car” //算路方式 选填}Page({ data: { routeInfo: routeInfo }})参数说明:起点:不填写或 startName=“我的位置” 或 startName=“当前位置” 或 startName=“currentLocation” 则插件会获取当前的定位位置作为起点位置发起算路,若正确填写起点信息,则以传入的起点信息发起算路。终点:必传参数,不正确传入则不会发起算路或者算路失败。算路方式:mode,目前支持三种算路方式,分别是:驾车(car),公交(bus),步行(walk);不传则默认发起驾车算路。注意:数据要在 data 中初始化,不要在 onLoad 中直接 setData,因为 onLoad 中直接 setData,properties 的 routeInfo 的 observer: function (newVal, oldVal),newVal 接收不到参数,导致参数报错,之后可以通过 bind 其他事件 setData 更新 routeInfo 达到变更起终点参数的效果。「腾讯地图」插件使用效果图如果你想了解更多「腾讯地图」插件详情,欢迎访问开发者社区插件版块相应页面(建议电脑访问):????https://developers.weixin.qq….手机端用户也可以扫码访问 ????内容来自:微信开放社区《小程序·小故事》栏目原作者:熊明钧任何问题,欢迎前往微信开放社区:https://developers.weixin.qq.com了解更多小程序开发相关内容,欢迎微信扫描下方二维码关注微信极客WeGeek公众号,共筑微信生态。 ...

November 14, 2018 · 1 min · jiezi

微信小程序黑客马拉松即将开始,来做最酷的 Mini Program Creators!

微信小程序黑客马拉松正式启动近日,小程序斩获一项世界级殊荣——作为一项全新的技术和应用创新,小程序首次获选世界互联网领先科技成果。目前小程序应用数量已超过 100 万,覆盖了 200 多个细分行业,日活用户达到 2 亿。微信小程序已经构建了一个完整的开发环境和开发者生态,有超过 150 万开发者进入小程序生态,在 2017 年带动就业 104 万,社会效应不断提升。小程序走进了高校计算机课堂,新职业「小程序员」也应运而生。小程序的蓬勃发展也使得「小程序人文化创业」兴起,小程序的技术难度降低,更多非技术人才加入,掀起了小程序全民创业热潮。正如马化腾作为腾讯公司代表上台领奖时说到:过去开发软件,我们常常要考虑不同开发环境的语言、设备的适配性和成本。现在,开发者可以在一个「类操作底层」去开发应用,打破了过去受限的开发环境,为「跨系统开发」这个世界难题给出了中国的解决方案,小程序创业者们迎来了新的机遇。由腾讯公司微信事业群主办、SegmentFault 承办的「微信小程序WeGeek Hackathon」(黑客马拉松)将于 2018 年 12 月 15 日 - 12 月 16 日在北京正式启动,本次黑客马拉松面向全球小程序开发者、爱好者,旨在通过微信小程序平台进行小程序的创新开发,共同建设小程序生态!做最酷的 Mini Program Creators本次黑客马拉松的主题是 Mini Program Creators,我们将召集最富有创造力的 开发者、产品经理、设计师,在 48 小时内 运用微信小程序框架,打造出一款 足够好玩、足够创新 的小程序。具体题目会分为多个方向,并在大赛前一周正式公布。黑客马拉松自诞生起就一直是开发者、设计师、创业团队的狂欢盛宴。小程序因其结构简单、搭建快速、开发成本低等特点,让两天内的快速开发成为了可能。在这场黑客马拉松的规定时间里,你可以充分发挥创造力,并与团队成员高度配合,从 0 开始创造出一个全新的产品,收获一个能够实现自己想法的小程序。你们准备好接受小程序的挑战了吗?加入微信小程序黑客马拉松,来做最酷的 Mini Program Creators!奖项设置大赛共设一、二、三等奖各一名,获奖团队将获得大赛奖金。一等奖 ¥102420二等奖 ¥102416三等奖 ¥1024*10此外,凡在规定时间内完成作品的参赛团队均可以获得微信大礼包一份,更多奖品内容持续公布中。参与对象本次黑客马拉松面向全国职业开发者、高校学生等小程序爱好者,同时还将招募部分产品经理和 UI 设计师,与开发者自由组队参赛。参赛者以个人身份报名,以团队身份参赛的每个成员都要单独报名。报名后官方会对报名人员进行筛选。团队规模每个团队 1-5 人,团队最高人限 5 人,一人只能参与一个团队。现场组队参赛者可提前组队,也可到现场自由组队。现场设有白板和便利贴,参赛者可在便利贴上写明自己擅长的技能、想要担任的团队角色,以便大家更快组队。活动时间与地点???? 2018年12月15日(周六)09:00至2018年12月16日(周日)17:00???? 北京腾讯众创空间(回龙观)报名参与微信扫描下方二维码关注微信极客WeGeek公众号,了解WeGeek Hackathon最新信息

November 13, 2018 · 1 min · jiezi

WeGeek | WePY 开源框架

今天前来专栏分享的极客,是腾讯微信支付团队。小程序公测一个月时,微信支付团队开源了小程序上的组件化开发框架 WePY,在 Github 上一经发布便受到了众多开发者的追捧,网上搜索「微信小程序 WePY 开源框架资源汇总」尽是网友们自发分享的相关干货。尽管 WePY 开源框架如今倍受推崇,回忆起开源的初衷,来自微信支付团队的 Gcaufy 还是表示:「WePY 开源框架的对外开源并不是要去分享一个很成功的解决方案,而是我认为这套方案能够解决在小程序开发中遇到的一些实际问题,并且希望能借助外界的力量去帮助一起完善这套方案。」接下来,让我们一起看看 WePY 开源框架背后的开发故事吧。如果你有一定的开发经验,会明显感受到小程序的开发十分容易上手——小程序本身提供一些特性如:模块化,模板,数据绑定等,极大地方便了习惯使用 MVVM 框架的用户。但同时,由于运行环境有限,小程序尚不能使用市面上的流行框架。在几个月的开发历程里,作者 Gcaufy 便一直希望可以设计出一套方案,更大可能地让小程序开发贴近于当下开发习惯,WePY 开源框架应运而生。WePY 开源框架的原理很简单:通过 WePY 开源框架开发的代码在经过编译后,能生成一份完美运行在小程序端的代码,使得小程序开发更贴近于传统 H5 框架开发,可以像开发 H5 一样支持引入 npm 包,并且支持组件化开发以及支持 JS 新特性等,实现类 Vue 的开发体验。WePY 开源框架实现小程序的预加载我们知道,传统的 H5 可以通过预加载来提升用户体验,那么小程序能够实现吗?答案是肯定的。在小程序中使用预加载,比在 H5 中实现起来更为简单方便,但也更容易被开发者忽视。传统 H5 在启动时,page1.html 只会加载 page1.html 的页面与逻辑代码,当 page1.html 跳转至 page2.html 时,page1 所有的 Javascript 数据将会从内存中消失。在 page1 与 page2 之间的数据通信只能通过 URL 参数传递或者浏览器的 cookie,localStorge 存储处理。而小程序在启动时,会直接加载所有页面逻辑代码进内存。即便 page2 可能都不会被使用,在 page1 跳转至 page2 时,page1 的逻辑代码 Javascript 数据也不会从内存中消失。page2 甚至可以直接访问 page1 中的数据。小程序的这种机制差异正好可以更好的实现预加载。通常情况下,我们习惯将数据拉取写在 onLoad 事件中。但是小程序的 page1 跳转到 page2,到 page2 的 onLoad 存在一个 300ms ~ 400ms 的延时。如下图:因为小程序的特性,完全可以在 page1 中预先拿取数据,然后在 page2 中直接使用,这样就可以避开 redirecting 的 300ms ~ 400ms了。如下图:对于上述问题,WePY 开源框架中封装了两种概念去解决:预加载数据用于小程序中 page1 主动传递数据给 page2,比如 page2 需要加载一份耗时很长的数据。我可以在 page1 闲时先加载好,进入 page2 时直接就可以使用。预查询数据用于避免于 redirecting 延时,在跳转时调用 page2 预查询。WePY 开源框架添加了 onPrefetch 事件,会在 redirect 之时被主动调用,这一改进扩展了生命周期;同时 onLoad 事件也添加了一个参数,用于接收预加载或者是预查询的数据:// params// data.from: 来源页面,page1// data.prefetch: 预查询数据// data.preload: 预加载数据onLoad (params, data) {}WePY 开源框架实现小程序的数据优化可能有开发者还不了解,其实小程序的视图层与逻辑层是完全分离的,这二者之间的通信全都依赖于 WeixinJSBridge 实现。如:开发者工具中是基于 window.postMessageiOS 中基于 window.webkit.messageHandlers.invokeHandler.postMessageAndroid 中基于 WeixinJSCore.invokeHandler数据绑定方法 this.setData() 亦然,于是很容易想到,频繁的数据绑定会不会导致通信的成本大大增加呢?为了验证 setData() 存在性能问题,微信支付团队做了一个相关测试:动态绑定 1000 条数据的列表进行性能测试,主要针对以下三种情况:最优绑定: 在内存中添加完毕后最后执行 setData() 操作。最差绑定: 在添加一条记录执行一次 setData() 操作。最智能绑定:不管中间进行了什么操作,在运行结束时执行一次脏检查,对需要设置的数据进行 setData() 操作。经过十次刷新运行测试后得出了以下结果:从测试结果可以明显看出,实现同样的逻辑,性能数据却相差 40 倍左右。通过分析测试结果,我们可以得知,在开发过程中,应当尽量避免同一流程内多次 setData() 操作。那么有什么优化方式呢?采取人工维护肯定能够实现,但当页面逻辑负责起来之后,即便花很大的精力去维护也不一定能保证每个流程只存在一次 setData(),可维护性也不高。因此,WePY 开源框架选择了使用脏检查去做数据绑定优化。虽然 WePY 开源框架在语法上借鉴了 Vue,原理则是完全不同的。比如 WePY 开源框架使用的是 ng 的脏检查设计,而不是使用的 Vue 的 getter,setter 等。用户不用再担心在流程里,数据被修改了多少次,只用在流程最后做一次脏检查,并且按需执行 setData() 即可。使用 WePY 开源框架在开发效率上的提升除了上述基于性能上做出的优化以外,WePY 开源框架也作出了一系列开发效率上的优化。支持丰富的编译器js 可以选择用 Babel 或者 TypeScript 编译。wxml 可以选择使用 Pug(原Jade)。wxss 可以选择使用 Less、Sass、Styus。支持丰富的插件处理可以通过配置插件对生成的js进行压缩混淆,压缩图片,压缩 wxml 和 json 已节省空间等等。支持 ESLint 语法检查添加一行配置就可以支持 ESLint 语法检查,可以避免低级语法错误以及统一项目代码的风格。生命周期优化WePY 开源框架添加了 onRoute 的生命周期。用于页面跳转后触发。 这一优化项是因为小程序中并不存在一个页面跳转事件。onShow 事件可以用作页面跳转事件,但同时也存在负作用,比如按 HOME 键后切回来,或者拉起支付后取消,拉起分享后取消都会触发 onShow 事件。优化事件传参原有的传参写法:<view data-alpha-beta=“1” data-alphaBeta=“2” bindtap=“bindViewTap”> DataSet Test </view>Page({ bindViewTap:function(event){ event.target.dataset.alphaBeta === 1 // - 会转为驼峰写法 event.target.dataset.alphabeta === 2 // 大写会转为小写 }})优化后:<view @tap=“bindViewTap(“1”, “2”)"> DataSet Test </view>methods: { bindViewTap(p1, p2, event) { p1 === “1”; p2 === “2”; }}更多详情可以参看 WePY 开源框架文档:https://tencent.github.io/wep…。WePY 开源框架2.0 计划目前 WePY 开源框架主要由微信支付团队内相关人员利用业余时间,与几个外部贡献者一起来维护。技术社区中有不少热心的贡献者,不仅自己参与,也会带来了一些新的贡献者力量,不时还会提供一些比较核心的功能。当被问及「WePY 开源框架 2.0 进度」问题时,微信支付团队表示现已将进入了 WePY 2.0 内测阶段,相信不久后就将与大家正式见面。「希望 2.0 是一个全新的,对得起开发者的版本。」了解更多小程序开发相关内容,欢迎微信扫描下方二维码关注微信极客WeGeek公众号,共筑微信生态。 ...

November 13, 2018 · 2 min · jiezi

开发一款即时通讯App,从这几步开始

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦本文由腾讯云视频发表于云+社区专栏关注公众号“腾讯云视频”,一键获取 技术干货 | 优惠活动 | 视频方案“晚上去哪吃饭啊?”桌面上来自一条晚上约饭的对话框——QQ。突然灵光一现,新出了优化的IM SDK,可以尝试着搭建一个类似QQ的即时通讯软件01注册账号腾讯云官网注册腾讯云账号,也可以使用QQ或者微信直接登陆02创建应用选择【产品】→【云通信】→【立即使用】→【创建应用接入】03SDK接入1、集成SDK【下载云通信SDK】包括IMSDK(云通信SDK)、TUIKit(基础界面库)2、生成UserSig在【基础配置】下载公私钥,使用【开发辅助工具】生成测试用户的UserSig3、初始化SDKAndroid代码 //应用启动时(一般为Application的onCreate)配置UIKit的基本配置,具体参数说明参考API BaseUIKitConfigs uiKitConfigs = new BaseUIKitConfigs(); uiKitConfigs.appCacheDir(Constants.APP_DIR_CACHE).audioRecordMaxTime(120) .disableAudioPlayedStatusIcon(true).disableAutoPlayNextAudio(true) .ChatProcessor(new PojoChatProcessor()); ILiveUIKit.init(this, uiKitConfigs);4、创建登陆界面Android代码 public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); //实例化登录面板 mLoginPanel = new LoginView(this); //将登录组件设置为登录Activity的基本布局,也可在布局文件xml中引用LoginView setContentView((View) mLoginPanel); //添加登录组件的动作事件,登录点击与注册点击 mLoginPanel.setLoginEvent(new ILoginEvent() { @Override public void onLoginClick(View view, String userName, String password) { //点击登录时业务自己的登录逻辑 } @Override public void onRegisterClick(View view, String userName, String password) { //点击注册时业务自己的注册逻辑 } }); }界面实图 5、创建会话列表布局文件 <!–在会话列表布局文件中引用会话列表组件,也可参考登录面板在代码中设置–><?xml version=“1.0” encoding=“utf-8”?><LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android" xmlns:app=“http://schemas.android.com/apk/res-auto" xmlns:tools=“http://schemas.android.com/tools" android:layout_width=“match_parent” android:layout_height=“match_parent” android:orientation=“vertical” tools:context=".main.MainActivity”> <com.tencent.qcloud.uikit.business.session.view.SessionPanel android:id=”@+id/session_panel” android:layout_width=“match_parent” android:layout_height=“match_parent” /></LinearLayout>Android代码 /*** 获取会话列表组件,初始化默认设置* 会话组件的默认设置已经实现了会话数据的拉取与处理(与IMSDK关联完成相关逻辑)* 开发者如为特殊要求直接初始化默认设置即可* 另会话组件提供的可扩展的事件和UI处理,具体可参考API文档*/sessionPanel = baseView.findViewById(R.id.session_panel);sessionPanel.initDefault();界面实图6、创建聊天界面Android代码//从布局文件中获取聊天面板组件chatPanel = mBaseView.findViewById(R.id.chat_panel);/** 会话组件的默认设置已经实现了会话数据的拉取与处理(与IMSDK关联完成相关逻辑)* 开发者如无特殊要求直接初始化默认设置即可* 另聊天面板组件提供的可扩展的事件和UI处理,具体可参考API文档*/chatPanel.initDefault();//生成聊天基本信息,如聊天对象的昵称,头像,最后一页聊天信息等BaseChatInfo info = getChatInfo();//设置基本信息,以便用户进入该页面时能即时展示相关信息chatPanel.setBaseChatInfo(info);界面实图7、群管理Android代码//从布局文件中获群管理面板组件GroupManagerPanel groupManagerPanel = mBaseView.findViewById(R.id.group_manager_panel);/** 群管理组件的默认设置已经实现了群管理相关的逻辑也操作(与IMSDK关联完成相关逻辑)* 开发者如无特殊要求直接初始化默认设置即可* 另聊群管理组件提供的可扩展的事件和UI处理,具体可参考API文档*/groupManagerPanel.initDefault();界面实图 通过以上几个步骤,一个拥有单聊、群聊的即时通讯App就这样完成了再次崇拜自己的动手能力,一天就能搭建完成一个APP,啦啦啦啦啦啦最后,了解一下经过优化后的新版本IM SDKIM SDK–体积优化1.android so体积<1M2.ios体积增量<2M–性能优化1.线程裁剪(单线程架构,减少线程切换和线程同步开支)2.cpu占用优化(线程裁剪、代码逻辑优化)–消息到达率深度优化业务逻辑层、会话策略层和网络层,实现四个九(99.99%)的消息到达率–数据监控用户级数据监控,实时跟踪和统计用户行为dau/mau功能统计用户分布–海外布点增加富媒体消息海外布点,为图片视频语音文件的上传下载提速–版本兼容与老版本兼容,实现无缝切换–UIKit插件一套多功能自定义界面库,实现会话列表、聊天、联系人、群管理、弹幕等界面,实现客户一天接入问答请问小程序即时通讯如何接入发送消息?相关阅读IM即时通讯实现原理iOS 即时通讯 + 仿微信聊天框架 + 源码开发一款即时通讯App,从这几步开始 【每日课程推荐】机器学习实战!快速入门在线广告业务及CTR相应知识 ...

October 29, 2018 · 1 min · jiezi

小游戏专场:腾讯云Game-Tech技术沙龙上海站顺利落下帷幕

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~本文由腾讯游戏云发表于云+社区专栏9月14日腾讯云GAME-TECH技术沙龙小游戏专场在上海顺利举办,此次技术沙龙由腾讯云的资深专家,以及Layabox游戏引擎的大牛为游戏从业者带来了众多技术干货,例如腾讯游戏云小游戏解决方案、微信小游戏入门与常见问题解惑、H5游戏语音解决方案、腾讯云数据库小游戏应用实践经验、微信小游戏运营及技术优化等。针对这些技术主题,专家大牛们与现场的游戏同仁们进行了深入的经验分享和讨论,并为游戏从业者解答了疑惑。小游戏作为游戏行业的风口,不仅具备强劲的吸金能力和市场潜力,而且开发门槛较低,但同时也面临着不少严峻的挑战。关于小游戏开发、运维、优化等技术要点问题,以及对于开发小游戏实战经验的需求,都成为了现场百余名游戏从业者热切关注的焦点。根据这些焦点问题,我们为大家整理了以下干货信息。小游戏作为行业新风口,腾讯云将会为小游戏提供怎样的技术支持和服务?曾有业内人士做过比较,开发一款APP游戏的时间与金钱成本,可以开发百款小游戏。当然,开发门槛低,也就导致了大量中小游戏开发商和独立开发者涌入到市场竞争中,所以大家都很关注开发成本和效率、运维是否高效的问题。对此,腾讯游戏云架构总监崔博为到场的游戏同仁们带来了腾讯云小游戏解决方案。腾讯游戏云架构总监崔博会上,崔博结合腾讯云小游戏解决方案,分别讲述了小游戏云开发框架和重度小游戏框架两方面的内容。在重度小游戏方面,他与现场游戏从业者分享了弹性扩缩容、高承载、加速、防护等问题及应对方案。此外,针对小游戏开发商,崔博还向大家介绍了腾讯云的扶持政策以及相关信息的获取途径。针对微信小游戏入门与常见问题,Layabox的大牛有何经验分享?知名游戏引擎厂商Layabox的合伙人李明,首先为到场的游戏开发商简要概况了小游戏的市场潜力和推广成本、开发成本等信息,使大家对小游戏市场有一个初步的认识。然后针对小游戏开发的基础入门技术与完整的开发流程进行分享,重点介绍了有关小游戏发布时的执行脚本与文件提取等实用功能,以及上传与审核的一些经验,李明为现场开发者作了详尽的讲述。Layabox合伙人李明此外,李明还分享了小游戏适配经验,包括4M包与网络动态资源加载、50M缓存管理、大项目分包、开放数据域等游戏从业者所关注的热点问题,李明也做了进一步的经验分享,解答了现场与会者的疑惑。面对日益增长的小游戏社交需求,腾讯云提供H5游戏语音解决方案随着小游戏市场规模的扩大,用户需求也不断提高,为适应小游戏社交新形态,并增加客户黏性,实现小游戏语音互通成为当下游戏开发商的迫切需求。为此,腾讯云GME资深工程师白兴师为现场与会者全面介绍了H5游戏语音解决方案,即如何从原生引擎转到H5做一个扩展。腾讯云GME资深工程师白兴师通过介绍GME及其架构,以及如何利用GME对产品进行封装,白兴师向大家全面剖析了腾讯云H5游戏语音解决方案。其中在GME架构这一主讲部分,他为现场的游戏从业者详细介绍了有关WebRTC的内容,其中包括P2P模型的问题及其解决方案、分配中心方案、如何维护创建房间状态、运营等经验分享。如何更好地运用腾讯云数据库,并结合到小游戏实践中?随着小游戏的持续火热,越来越多的游戏开发者开始关注如何更好地使用云数据来承载小游戏项目。腾讯云资深数据库架构师田冬雪,结合了自身10年有关数据库的从业经验,针对小游戏开发商对数据的需求以及小游戏的业务特点,与大家一起探讨了在小游戏项目中使用云数据库的经验技巧。腾讯云资深数据库架构师田冬雪对于小游戏快速部署的需求和爆发式增长的特征等,田冬雪向大家介绍了腾讯云数据库所具备的快速获取数据库实例、扩展性、读写分离、回档、灾备等功能。此外,通过串联前面的内容点,他还结合分析了两个真实案例,使大家进一步了解如何更好地使用云数据来承载小游戏项目。针对微信小游戏的运营和技术两方面,该如何进行优化?Layabox的合伙人李明,再次为大家带来关于如何在微信小游戏中进行运营优化和技术优化的经验分享。针对游戏创意成本高的现状,李明认为小游戏的优势在于依托微信关系链的裂变,能够快速生产并验证游戏产品,从而进行流量的变现。对此,他向现场游戏从业者分享了小游戏关键的几个数据指标,其中包括留存数据、裂变数据、分享率与分享转化率、题材选型、游戏玩法等,并结合自研产品的案例,向大家讲述在运营优化方面的重点在于创意和流量裂变。在技术优化板块上,李明向大家介绍了LayaAir引擎的性能优化,其中包括批次合并、自动大图合集、内存优化、加载优化等方面的优势。通过此次分享会,李明为现场的游戏开发商带来了有关微信小游戏在运营和技术优化层面的经验。此次上海站小游戏专场技术沙龙上,各技术专家为游戏行业的同仁们带来了关于小游戏开发、运维、优化等方面的技术分享,并与现场游戏开发者们进行了深入讨论、解答了大家有关小游戏的疑惑。下一站腾讯云GAME-TECH游戏开发技术沙龙,我们长沙见!问答微信小游戏与传统的手机游戏有什么区别?相关阅读聚焦小游戏,腾讯游戏云GAME-TECH 技术沙龙与您相约上海游戏出海,如何避开DDoS这座暗礁?《堡垒之夜》畅爽体验的秘诀了解一下! 【每日课程推荐】机器学习实战!快速入门在线广告业务及CTR相应知识

September 27, 2018 · 1 min · jiezi

张腾:腾讯云融合通信应用场景及案例分享

张腾,腾讯通信云高级产品经理,先后负责过手机、智能硬件等终端产品,对运营商、即时通信、音视频产品均有了解,负责产品场景话包装,对融合通信的应用场景具有较深了解。如何帮助这些很大的企业,基于我们融合通信的方案帮助他们去实现他们想要的,提高效率这个核心的诉求。我们也整理出来了一些核心的挑战。主要我们分成四个部分,一个部分是关于企业内部沟通的一些挑战的方面,以及他们针对客户做营销一些挑战,同时还有包括像不同企业之间希望提高企业之间的效率的挑战,最后我们也是基于他们企业一些诉求提供了我们对于他们的整套集成方案。这些是企业内沟通的挑战,首先大家可能都会遇到过,企业内部可能很多APP,尤其通信类的,包括像微信、QQ、钉钉,但是你会发现每一个自己员工在使用APP的时候都有自己爱好,有些人就用QQ,有些人就用微信,大家沟通起来会降低很多效率。还有另外一块是因为大家使用基于微信、QQ的联系方案,所以大家在找人的时候没有办法去很好很快速的找到自己要对应的人,没有自己的架构体系支撑他们寻找到快速对接的人。同时还有像包括企业内部多系统,每一套系统流程全部是独立的,所以说可能某一个单子下来,需要在几个系统里面同时组单,导致整个业务流程相当的耗时。另外就是销售,大家没办法掌握。可能很多销售说,我现在出去见客户了,其实大家并不知道他在干什么。还有移动安全,因为移动安全大家都做公网,很多人都会担心这种信息泄露,外部沟通不便,受到人工影响很大,有些人在离职之后,他所有记录全部就消失掉了,可能跟着这个人走了,没有办法进行有效的留存。这是我们跟客户进行沟通了之后筛选出来几个比较重要的挑战,对于企业内部沟通的。对于我们客户跟企业之间,企业跟我们消费者之间沟通,企业更需要什么,首先他们需要是精准匹配精准营销的能力,他们希望有人可以告诉他们,他们目标客户是谁,谁能买他们产品,他们也需要数据支撑他们如何有效进行市场运作,以及品牌的运作,实现他们品牌的优势。另外他们销售转化,通过什么样的方案,可以实现更多消费者购买他们的产品。最后就是他们希望有更多宣传渠道,大家经常见到是系统推送,外部中心,短信等等多通道的营销手段使企业可以触达更多客户,实现他们整个的营销的闭环。首先对于很多企业来说,缺乏有效的沟通手段,大家全部都是通过刚才说的微信、QQ,只能去找到独立的一些人,很难去看到对方的整个部门是什么情况,是不了解的,包括他们部门在对方体系里面是一个什么样的地位,或者他们的从属是什么样子。每个部门是不一样的,所以会导致我们在沟通的时候缺乏效率。另外一个就是刚才说到寻找对方企业人员难如登天,在沟通的时候没有办法找到很多的资源,另外就是可能销售对接上之后发现采购去对接了,或者其他部门同时也对接的时候,很难找到有效的对接人,浪费大量时间也没有找到核心的人员,进行有效的沟通。另外就是采购销售离职之后企业之间会失联,销售在走了之后所有关于这个企业之间的对接就全部停掉了,后续的人可能会很难接起来,不知道找谁,或者之前的客群关系做成什么样子会没有人知道。另外就是缺乏上下游有效管理,对于我们供应链,对于我们的渠道,没有办法很好实现管控,就导致信息孤岛。同时整个数据和信息安全无法得到保证,大家很多时候都是在微信群、QQ群里沟通,可能这种对于信息的保护,包括像沟通出现问题的时候,进行问题信息的回溯的时候出现很多问题,没有办法找到当时可能责任人是谁,很难实现这种安全,包括信息的留存。所以说很多企业其实从他们的底层来看,他们为了高效引入了像OA系统,视频会议系统,呼叫中心包括CRM、HRM,然而通过这种手段反而导致他们一些业务分散,和一些紧耦合,不得不依赖所有系统打通整套流程,反而拉低他们效率,从我们这边来看,融合的核心就是帮助整个企业形成一种高级程、松耦合的状态,提高他们的效率。所以说针对我们一些企业,我们也提出了我们会融合独立系统组件,提高他们核心效率,可以看到在我们底层,会基于整个方案将OA、呼叫中心、视频组件、包括RM系统在实现打通,通过一些API调用,实现OA、HRM、CRM系统对接。同时在应用层,我们会去帮客户实现他们移动化办公,比如说他们现在需要多终端办公需求,还有像协同的终端系统去应用于客服与知乎之间对接,还有基于视频会议,员工数据同步,他们会把他们接触到的客户全部同步到自己公司的系统里面,保证员工系统留存。同时还有像专属客服座席,智能客服等等。我们像文字、语音、视频多通道的融合,帮助客户从上到下建立一个基于内部的多端在线的移动办公,另外基于对外整套客服系统,同时基于企业外部可以实现企业外部跟上下游之间的沟通和合作。其实从整个需求来看,我们最终的目标是为了提高整个公司的效率,我们从接触到的很多需求来看,大家提出都是基础需求,但是如果说我们从基础需求上筛选,我们发现大家的需求无外乎就是这几点,一个是员工办公移动化,另外就是我们客户的多渠道对接服务,另外就是我们业务的无缝对接。其实最终也就是为了提高效率和降低成本,这个就是我们通过跟很多客户了解以后,我们去考虑到融合通信到底给客户带来什么。我们也是提出了一些自己的看法,核心就是融合通信从底层来看,其实就是打通我们传统IP与传播的电信通信的壁垒,另外打通企业内部沟通壁垒,同时也打破了企业间沟通的壁垒,同时也是有多种通讯方案相互独立的壁垒,最后打破人与机器沟通的壁垒。可以看到从我们对外打破IP与传统电信通信壁垒来看,其实苹果的Imessage,实现了IP跟我们传统电信的打通。例如收发表情,在苹果用户之间是通过他们的系统进行传输,如果给安卓用户发,安卓用户收到是彩信,其实就是说把相关的IP和传统电信实现了打通。另外整个打通企业内部沟通壁垒,之前会把整个企业通信部包括PSTN进行导入,用户之间可以通过公司总机实现快捷拨号找到对应的同事,实现快速的沟通,同时也会基于我们企业微信整套系统,把公司所有同事放在里面,避免了再找不到人的时候随便去问,或者说通过关系,很难去实现有效沟通的场景。另外我们说打破了企业间沟通的壁垒,通过我们这种融合通信方案,可以把自己上下游相关企业内部通信录,权限的选择开放给本公司,尤其是重要部门,像销售、采购重要的部门可以通过这种企业间的通信录实现快速的对接,同时基于我们企业微信会进行消息留存,保证在对接过程中如果出现问题我们是可回溯可以找到当时责任方是谁。我们打破了多种通讯方案的壁垒,很多指挥中心的场景,不仅仅需要我们的IM,还有像音视频,同时还有像对讲机等等一系列通信手段实现了打通,把全部的通信方案进行融合,帮助客户在不同场景之下信息的沟通。同时我们现在也打破了人与机器相沟通的壁垒,之前我们一个很明显的例子,我们之前所有客服都是人工客服,然而现在基本上都已经全部是机器人客服为主,客户通过我们融合通信方案,实现了人和机器之间的沟通。问答云通信有哪些功能?相关阅读破局人工智能:构建AI,与腾讯云一起探索语音应用场景“融而开放、合以创新”——与腾讯云一起探索融合通信小白也能玩转Kubernetes 你与大神只差这几步 【每日课程推荐】机器学习实战!快速入门在线广告业务及CTR相应知识此文已由作者授权腾讯云+社区发布,更多原文请点击搜索关注公众号「云加社区」,第一时间获取技术干货,关注后回复1024 送你一份技术课程大礼包!海量技术实践经验,尽在云加社区!

September 25, 2018 · 1 min · jiezi

关于iOS 11.x微信连wifi流程中,在Portal页无法拉起微信问题的简单记录

标题挺长,踩过坑的应该看的明白。不过限于目前所做产品流程的限制,我并没有解决掉这个问题,只是简单说一下相应的思路。iOS的系统浏览器是Safari,用于Portal认证的则是CNA(Captive Network Assistant),二者的区别在于前者可以打开wachat:这种私有协议头网址,后者无法打开并且限制很多,比如无法使用alert()、无法正常使用window.open()(只能做跳转)等等。问题的症结在于在新版的CNA中是不认wechat:这样的私有协议头的,所以自然也就拉不起来微信。解决时需要引导用户点击a标签<a target="_system"></a>触发Safari,然后再在Safari拉起微信就行了。我目前的portal触发逻辑是,客户端连到wifi上回触发landing,首先返回码设定为401用于触发客户端的portal页面,同时判断客户端UA,如果是部分安卓或iOS就渲染landing实体页(landing.ejs),页面的title和body均为“Success”以作为iOS欺骗(并且会加快从连接到弹出portal的响应时间);js部分,ios是直接打开认证URL,针对部分安卓则是加了判断document.visibilityState == ‘visible’时触发跳转的事件,用来解决不弹portal的问题。但由于点击按钮之后就直接进到js拉微信认证的流程了(少一步引导拉起微信),所以其实需要部分变更产品流程才行(这个版本暂时没戏)。参考链接:iOS: Open a Welcome Page in Safari, not CNA微信连WI-Fi解决ios无法呼出微信

September 1, 2018 · 1 min · jiezi

风口上的小游戏还有怎样的发展空间?7位腾讯技术专家为你解答

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~本文由腾讯游戏云发表于云+社区专栏8月25日腾讯云Game-Tech技术沙龙在北京举办,腾讯云资深专家与知名游戏引擎Layabox的大咖为游戏行业同仁们带来以“小游戏”为主题的开发技术分享会。来自双方的资深技术专家从腾讯云小游戏解决方案、LayaAir引擎及性能优化、H5实时语音解决方案、LayaAir3D性能优化、游戏储存技术、多人对战小游戏研发经验,以及如何玩转QQ玩一玩平台等方面的议题,与到场的游戏行业从业者进行深度的探讨。小游戏作为新一轮风口,有着强大的市场潜力,受到了游戏产业各方的极大关注。本次沙龙吸引到百余名游戏开发技术人员,我们根据现场讨论的热点话题,为大家整理了以下内容。腾讯游戏云针对小游戏的解决方案曾有业内人士做过比较,开发一款APP游戏的时间与金钱成本,可以开发百款小游戏。当然,开发门槛低,也就涌入了大量中小开发商和独立开发者参与市场竞争。 面对游戏开发者关注的小游戏开发成本、效率与运维等方面的问题,腾讯游戏云产品总监王永和向开发者全面讲解腾讯云小游戏解决方案,包括如何利用腾讯云工具快速开发小游戏、如何提高小游戏的下载效率、如何从容应对因社交传播导致小游戏瞬间爆发所带来的运维困境。腾讯游戏云产品总监王永和此外,王永和还提到了腾讯云和腾讯小游戏的部门共同打造的一个平台——TCB,是一个专门为微信小程序/小游戏开发和运维推出的应用开发平台,提供一系列的开发组键及PaaS服务,与微信客户端、 IDE 深度集成,同时支持业务服务注册和管理机制,极大提高小游戏开发和运维的效率。同时,基于微信小游戏社交化的特点,以及弹性扩缩容和高并发的承载等方面的需求,他也提到了腾讯游戏云在小游戏生态圈和游戏架构方面对应作出的优化改进。LayaAir2.0引擎的性能特点负责LayaAir引擎与IDE研发的合伙人朱春阳为大家深入介绍了LayaAir引擎原理和进阶功能,以及如何使用LayaAir引擎发挥出极致性能的优化原则与注意事项,并针对LayaAir 2.0引擎及IDE新特性进行了详细的介绍。LayaAir引擎与IDE研发的合伙人朱春阳朱春阳指出,LayaAir引擎在设计之初的理念为:化繁为简、极致性能。所以该引擎API精简易上手,在事件、加载、内存与性能等处都有着极致的优化,是大型游戏的首选引擎。并且是支持语言最全面的HTML5与小游戏引擎。即将推出的LayaAir 2.0引擎在继承了1.0的优势基础上,通过组件化,物理系统可视化,3D场景编辑可视化等重要功能的IDE与引擎升级,让引擎的性能更强,易用性大幅度增强。尤其是3D方面,1.0引擎的3D已经是当前最成熟的HTML5 3D引擎,市场中HTML5和小游戏的市场占有率超过96%。成为3D小游戏开发的首选引擎,而2.0,不仅有性能上的极致优化提升,更是增加了150多项功能。支持了PBR材质与动画融合等,满足开发FPS与高精度大型3D游戏的需求。另外,朱春阳也提到与LayaAir 2.0引擎同时发布的还有一个LayaCloud产品,它集成了房间管理、战斗匹配、帧同步、自定义服务器脚本等特性,可以让游戏前端开发者无需部署服务器环境,无需了解服务器语言,在IDE中通过调用API接口,就可以开发出联网游戏。腾讯云H5游戏语音解决方案随着小游戏市场规模不断扩大,用户群体日益递增,其社交需求也正逐渐提升,语音能力支持也将会是游戏开发者所面临的一个问题。腾讯云GME资深工程师曾维亿全面介绍了腾讯云H5游戏语音解决方案及其优势所在,为开发者提供全面透彻的技术讲解与支持。腾讯云GME资深工程师曾维亿腾讯云游戏多媒体引擎 GME(Gaming Multimedia Engine) 致力于为游戏提供语音服务,其中的H5实时语音模块有三个特点:稳定的连接能力,优秀的音频质量和非常低的接入门槛。接入GME H5模块有助于提升小游戏用户粘性,设计小游戏社交新形态。曾维亿也带来关于GME H5的设计架构和实现思路的分享,看看GME是如何构建高可用的全球接入网络;如何保证通话音质以及降低对游戏本身的影响;以及如何快速接入GME。LayaAir 3D引擎的新特性负责LayaAir 3D引擎研发的Layabox合伙人郭磊为大家重点介绍了LayaAir 2.0引擎3D物理、3D材质、3D动画的新增功能,并针对3D游戏开发注意事项,以及游戏内存与性能的分析和优化方式进行分享。LayaAir 2.0 3D相对于1.0来说进行了诸多改进和提升,具备性能高、简单易用、功能强大和开放的特点;尤其是在3D引擎开放性方面,显著地优化了自定义材质和一些渲染管线的开放。Layabox合伙人郭磊郭磊还深入地为大家介绍了该引擎新增的功能,例如材质功能新增、纹理功能新增、动画多层混合功能新增、物理功能新增、批量资源释放等新增功能、RigidBody,以及动画更新机制调整为实时插值、针对美术资源处理和物理组件等的优化。腾讯Tcaplus游戏存储解决方案腾讯Tcaplus(游戏存储)资深工程师余洋首先分析了小游戏存储系统的特点,然后针对小游戏存储面临的问题,包括Tcaplus功能和技术实现、Tcaplus在游戏领域的应用等,向大家介绍了Tcaplus作为专为游戏设计的 NoSQL 分布式数据存储服务,在追求高性能的同时,也可以节省成本,并针对游戏爆发增长和长尾运维特点提供不停机扩缩容、备份容灾、快速回档等全套解决方案。腾讯Tcaplus资深工程师余洋此外,余洋还分享了过往的一些客户案例,最后为大家介绍了API接入的使用方法。为小游戏在大储存方面会遇到的难题,提供了详细的解决方案。《全民打雪球》的适配与开发经验拥有非常丰富的HTML5大型项目研发经验、微信小游戏适配经验、QQ玩一玩适配经验的《全民打雪球》项目主程王松,以腾讯独代产品《全民打雪球》在微信小游戏中的适配与开发经验为例,为小游戏开发者带来对战类微信小游戏在开发与适配中遇到的常见问题的解决方案。《全民打雪球》项目主程王松QQ 玩一玩平台的核心能力除了微信小游戏外,腾讯旗下还有一个依托手机QQ的游戏平台——QQ玩一玩平台。腾讯资深工程师李泽松为大家介绍了QQ 玩一玩平台的现状及核心能力,并通过在QQ玩一玩平台的案例,来讲解如何选择平台制作游戏,给大家带来了玩一玩平台的最新动向预告。腾讯资深工程师李泽松QQ玩一玩平台可以针对QQ轻游戏的特点进行更丰富的拓展,李泽松向大家介绍了针对内存、玩法等问题的完备解决方案,而对于资源卡顿、游戏包过大、调试困难这三个痛点问题,也向大家介绍了后续将推出的功能。 在7位技术嘉宾分享了小游戏行业的发展趋势、小游戏技术研发和运维经验之后,也与到场的游戏同仁们进行深度交流,解答技术咨询问题。腾讯云Game-Tech游戏开发者系列沙龙下一站,我们上海约!查看沙龙现场内容,速戳:https://v.qq.com/x/page/z0770…问答策略游戏服务器概念是什么?相关阅读3行代码,为QQ轻游戏加上语音互动能力实时语音趣味变声,大叔变声“妙音娘子”Get一下内行看门道:看似“佛系”的《QQ炫舞手游》,背后的音频技术一点都不简单 【每日课程推荐】新加坡南洋理工大学博士,带你深度学习NLP技术

September 1, 2018 · 1 min · jiezi

H5页面在微信端的分享

H5页面在微信端的分享微信分享,咋一看好像很复杂,实则非常简单。只需要调用微信官方出的微信jssdk,加上些许配置,就可以实现h5页面在微信上的分享,官方文档地址为:https://mp.weixin.qq.com/wiki…一、获取基本信息找到已有公众号的appid,根据这个appid和url向后端发起请求,拿到配置所需要的参数:timestamp、noncestr和signature。二、实现1、页面引入JS-SDK文件通过script标签,引入微信官网的JS-SDK文件<script src=“https://res.wx.qq.com/open/js/jweixin-1.2.0.js" type=“text/javascript”></script>2、基本配置wx.config({ debug: false, // 是否开启调试模式 appId: appid, //appid timestamp: timestamp, // 时间戳 nonceStr: noncestr, // 随机字符串 signature: signature, // 签名 jsApiList: [ ‘onMenuShareTimeline’, ‘onMenuShareAppMessage’, ‘onMenuShareQQ’, ‘onMenuShareWeibo’, ‘onMenuShareQZone’ ] // 需要使用的JS接口列表})3、使用wx.ready(function(){ // 分享给好友 wx.onMenuShareAppMessage({ title: title, // 分享标题 desc: desc, // 分享描述 link: link, // 分享链接 imgUrl: imgUrl, // 分享图标 success: function () { doShareDone() }, cancel: function () { doShareCancel() } }) // 分享到朋友圈 wx.onMenuShareTimeline({ title: title, // 分享标题 link: link, // 分享链接 imgUrl: imgUrl, // 分享图标 success: function () { doShareDone() }, cancel: function () { doShareCancel() } })})// 分享成功回调function doShareDone () { console.log(‘分享成功’)}// 取消分享回调function doShareCancel () { console.log(‘取消了分享’)}三、调试wx.config里的debug字段设置为true时,就可以进行调试。调试要用到微信开发者工具,选择公众号网页项目,输入页面地址就可以了。四、遇到的问题及解决方案微信JS-SDK说明文档的附录5里有大部分问题的解决方案,在这里我列出我遇到的几个上面没有给出解决方案的。1、Uncaught TypeError: Cannot read property ‘config’ of undefined解决:html页面单独引入了sdk,并且组件统一也引入了一遍sdk,导致问题,删除其中之一。2、Uncaught (in promise) TypeError: Cannot read property ‘ready’ of undefined解决:同问题1。3、invalid signature解决:如果文档里的方法都没有解决这个问题,还有一种方法,先设置一种最基础的配置,使其config ok,然后再设置一遍自己需要的有各种参数的分享文案,这样能绕过配置,成功分享。说的可能有点拗口,简单点理解就是,页面只要有一个config成功的配置,就可以再继续配置其它分享,哪怕这个分享配置的signature无效。 ...

August 30, 2018 · 1 min · jiezi