
h5+、mui、app开发基础+实战教程都在这儿!

《JavaScript 快速提高视频教程》 js基础快速提高课程 【免费】
http://www.hcoder.net/course/info_229.html
《MUI 视频教程》【免费】
http://www.hcoder.net/course/info_211.html
《h.js 视频教程》【免费】
http://www.hcoder.net/tutorials/info_147.html
《HTML 5 开发教程》【免费】
http://www.hcoder.net/course/info_212.html
《APP开发实例教程 - 窗口切换 》【免费】
http://www.hcoder.net/course/info_218.html
《HBuilder 8.0.1 APP开发 - 新功能全接触》【免费】
http://www.hcoder.net/course/info_227.html
--------- 实战收费教程 ------------------------
《仿腾讯新闻客户端》- MUI+VUE.JS H5+ APP 实战教程
http://www.hcoder.net/course/info_240.html
MUI、H5 APP 实战教程 - 仿《有道词典》
https://ke.qq.com/course/194834
H5 跨平台APP开发电商项目实战教程 -《仿京东优选商城》
https://ke.qq.com/course/225830
更多课程中心
http://www.hcoder.net/course
《JavaScript 快速提高视频教程》 js基础快速提高课程 【免费】
http://www.hcoder.net/course/info_229.html
《MUI 视频教程》【免费】
http://www.hcoder.net/course/info_211.html
《h.js 视频教程》【免费】
http://www.hcoder.net/tutorials/info_147.html
《HTML 5 开发教程》【免费】
http://www.hcoder.net/course/info_212.html
《APP开发实例教程 - 窗口切换 》【免费】
http://www.hcoder.net/course/info_218.html
《HBuilder 8.0.1 APP开发 - 新功能全接触》【免费】
http://www.hcoder.net/course/info_227.html
--------- 实战收费教程 ------------------------
《仿腾讯新闻客户端》- MUI+VUE.JS H5+ APP 实战教程
http://www.hcoder.net/course/info_240.html
MUI、H5 APP 实战教程 - 仿《有道词典》
https://ke.qq.com/course/194834
H5 跨平台APP开发电商项目实战教程 -《仿京东优选商城》
https://ke.qq.com/course/225830
更多课程中心
http://www.hcoder.net/course
收起阅读 »

直播业务指南
*注意要使用HBuilderX而不是HBuilder
引言
直播是很多开发者的需求。
HTML5的video,虽然可以播放流媒体,但不支持rtmp等常用直播格式。更无法实现推流,就是实时流式上传视频。
5+App、uni-app给开发者提供了完整的直播解决方案。
HTML5Plus规范提供了plus.video扩展规范,实现了原生的视频播放和推流录制上传。
HTML5Plus的规范是通行规范,可支持任何直播云服务厂商的直播服务器。
但又拍云公司作为HTML5中国产业联盟成员,为HTML5plus的开发者提供了更多完善服务。
- 注册优惠
点此链接注册,可得众多优惠。
a) 认证完毕后赠送 61 元免费代金券;
b) 首次充值后,奖励充值金额 10% 代金券
c) 一周后再赠送200元的代金劵
以上优惠不是三选一,是全都有。有效期1个月时间。 - 便捷的服务器搭建
无需关心rtmp服务器的搭建和网络cdn的优化,注册后提供自己的直播推流和播放的域名,做cname映射到又拍云的服务器,然后自己随便定义二级目录地址就可以用了。
详见又拍云文档http://docs.upyun.com/live/guide/
代码示例-推流上传(live-pusher)
直播推流控件会调用手机摄像头采集视频流,编码后通过rtmp协议提交到直播服务器。
- 创建直播推流控件
- uni-app下nvue页面
uni-app下的nvue页面在uni-app编译模式下,实现了live-pusher组件及uni.createLivePusherContext API
- uni-app下nvue页面
并实现了一套代码兼容App和小程序,具体参考上述组件及API文档。
-
uni-app下的vue页面
app平台的vue页面中使用直播推流,不能使用uni的api,而需要使用plus的APIconst currentWebview = this.$mp.page.$getAppWebview() var pusher = plus.video.createLivePusher("", { url:'rtmp://testlivesdk.v0.upaiyun.com/live/upyunb', top:'100px', left:'0px', width: '100%', height: '300px', position: 'static' }); currentWebview.append(pusher);
-
5+App模式示例:
在页面中直播推流控件需要绑定div确定位置及大小,创建直播推流控件需要传入div的id,示例如下:<html> <head> <meta charset="utf-8"/> <meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/> <title>Hello H5+</title> <script type="text/javascript"> var pusher = null; // H5 plus事件处理 function plusReady(){ // 创建直播推流控件 pusher = new plus.video.LivePusher('pusher',{url:'rtmp://testlivesdk.v0.upaiyun.com/live/upyunb'}); // 监听状态变化事件 pusher.addEventListener('statechange', function(e){ console.log('statechange: '+JSON.stringify(e)); }, false); } document.addEventListener('plusready', plusReady, false); </script> </head> <body> <br/> <div id="pusher" style="width:300px;height:400px;background-color:#000000;margin:auto"></div> </body> </html>
其中new plus.video.LivePusher()第一个参数'pusher'为绑定div的id值,第二个参数中的url属性值为直播推流服务器地址,必须为rtmp协议。创建后返回直播推流控件(LivePusher)对象,后续可通过此对象进行操作控制。
使用HBuilderX新建5+App项目时自带的Hello H5+模板,真机运行,可以看到video示例,里面有推流和播放的示例代码。
- 采集直播推流提交到服务器
创建直播推流控件后可通过setOptions方法更新直播控件参数,如下更新直播推流服务器地址:pusher.setOptions({url:'rtmp://新的直播推流服务器地址'});
配置完成后调用start方法开始采集直播流提交到服务器:
pusher.start();
推流时支持美颜、摄像头切换。不支持其他特效滤镜。
目前不支持录屏直播,无法实现手机录制。除非使用原生sdk自行开发离线打包。
目前暂不支持直播连麦功能。
更多API参考文档http://www.html5plus.org/doc/zh_cn/video.html#plus.video.LivePusher。
推流到直播服务器后可通过原生视频播放控件进行播放。
代码示例-使用视频播放控件播放直播视频流
HTML5标准的video是无法播放直播视频流的,所以需要使用原生增加的播放控件。
HTML5plus扩展的原生视频播放控件(也是uni-app的App端自带的)支持视频格式包括mp4和flv,视频传输协议支持http/https和rtmp/hls/rtsp(直播流)
-
创建视频播放控件
- uni-app模式
uni-app模式直接使用<video>组件进行播放,无需其他复杂设置。 - 5+App模式
在页面中视频播放控件需要绑定div确定位置及大小,创建视频播放控件需要传入div的id,示例如下:<!DOCTYPE HTML> <html> <head> <meta charset="utf-8"/> <meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/> <title>Hello H5+</title> <script type="text/javascript"> var video = null; // H5 plus事件处理 function plusReady(){ // 创建视频播放控件 video = new plus.video.VideoPlayer('video',{ src:'rtmp://live.hkstv.hk.lxdns.com/live/hks' }); } document.addEventListener('plusready', plusReady, false); </script> </head> <body> <br/> <div id="video" style="width:98%;height:300px;background-color:#000000;margin:auto"></div> </body> </html>
其中new plus.video.VideoPlayer()第一个参数'video'为绑定div的id值,第二个参数中的src属性值为要播放的直播视频地址,直播视频必须为rtmp协议。创建后返回视频播放控件(VideoPlayer)对象,后续可通过此对象进行操作控制。
- uni-app模式
-
播放视频流
创建视频播放控件后可通过setOptions方法更新播放控件参数,如下更新视频服务器地址:video.setOptions({src:'新的视频服务器地址'});
用户可以点击播放控件上的播放按钮进行播放,也可调用play方法进行播放:
video.play();
如果想在视频上绘制一些内容,比如滚动的聊天记录,5+App可以在上面创建一个透明webview,具体代码在Hello H5+的video示例里有;uni-app可以在上面创建一个subnvue,在HBuilderX1.9.10+版本中自带的hello uni-app - API - 界面 - 原生子窗体中也有示例。
包括防盗播的跑马灯也可以这么做。
更多API参考文档http://www.html5plus.org/doc/zh_cn/video.html#plus.video.VideoPlayer。
三方示例模板
这个是插件市场里三方开发者做的直播业务模板,开源,可以参考:http://ext.dcloud.net.cn/plugin?id=226
还有一些开发者封装了三方原生sdk,比如腾讯直播sdk,可以在插件市场获取
*注意要使用HBuilderX而不是HBuilder
引言
直播是很多开发者的需求。
HTML5的video,虽然可以播放流媒体,但不支持rtmp等常用直播格式。更无法实现推流,就是实时流式上传视频。
5+App、uni-app给开发者提供了完整的直播解决方案。
HTML5Plus规范提供了plus.video扩展规范,实现了原生的视频播放和推流录制上传。
HTML5Plus的规范是通行规范,可支持任何直播云服务厂商的直播服务器。
但又拍云公司作为HTML5中国产业联盟成员,为HTML5plus的开发者提供了更多完善服务。
- 注册优惠
点此链接注册,可得众多优惠。
a) 认证完毕后赠送 61 元免费代金券;
b) 首次充值后,奖励充值金额 10% 代金券
c) 一周后再赠送200元的代金劵
以上优惠不是三选一,是全都有。有效期1个月时间。 - 便捷的服务器搭建
无需关心rtmp服务器的搭建和网络cdn的优化,注册后提供自己的直播推流和播放的域名,做cname映射到又拍云的服务器,然后自己随便定义二级目录地址就可以用了。
详见又拍云文档http://docs.upyun.com/live/guide/
代码示例-推流上传(live-pusher)
直播推流控件会调用手机摄像头采集视频流,编码后通过rtmp协议提交到直播服务器。
- 创建直播推流控件
- uni-app下nvue页面
uni-app下的nvue页面在uni-app编译模式下,实现了live-pusher组件及uni.createLivePusherContext API
- uni-app下nvue页面
并实现了一套代码兼容App和小程序,具体参考上述组件及API文档。
-
uni-app下的vue页面
app平台的vue页面中使用直播推流,不能使用uni的api,而需要使用plus的APIconst currentWebview = this.$mp.page.$getAppWebview() var pusher = plus.video.createLivePusher("", { url:'rtmp://testlivesdk.v0.upaiyun.com/live/upyunb', top:'100px', left:'0px', width: '100%', height: '300px', position: 'static' }); currentWebview.append(pusher);
-
5+App模式示例:
在页面中直播推流控件需要绑定div确定位置及大小,创建直播推流控件需要传入div的id,示例如下:<html> <head> <meta charset="utf-8"/> <meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/> <title>Hello H5+</title> <script type="text/javascript"> var pusher = null; // H5 plus事件处理 function plusReady(){ // 创建直播推流控件 pusher = new plus.video.LivePusher('pusher',{url:'rtmp://testlivesdk.v0.upaiyun.com/live/upyunb'}); // 监听状态变化事件 pusher.addEventListener('statechange', function(e){ console.log('statechange: '+JSON.stringify(e)); }, false); } document.addEventListener('plusready', plusReady, false); </script> </head> <body> <br/> <div id="pusher" style="width:300px;height:400px;background-color:#000000;margin:auto"></div> </body> </html>
其中new plus.video.LivePusher()第一个参数'pusher'为绑定div的id值,第二个参数中的url属性值为直播推流服务器地址,必须为rtmp协议。创建后返回直播推流控件(LivePusher)对象,后续可通过此对象进行操作控制。
使用HBuilderX新建5+App项目时自带的Hello H5+模板,真机运行,可以看到video示例,里面有推流和播放的示例代码。
- 采集直播推流提交到服务器
创建直播推流控件后可通过setOptions方法更新直播控件参数,如下更新直播推流服务器地址:pusher.setOptions({url:'rtmp://新的直播推流服务器地址'});
配置完成后调用start方法开始采集直播流提交到服务器:
pusher.start();
推流时支持美颜、摄像头切换。不支持其他特效滤镜。
目前不支持录屏直播,无法实现手机录制。除非使用原生sdk自行开发离线打包。
目前暂不支持直播连麦功能。
更多API参考文档http://www.html5plus.org/doc/zh_cn/video.html#plus.video.LivePusher。
推流到直播服务器后可通过原生视频播放控件进行播放。
代码示例-使用视频播放控件播放直播视频流
HTML5标准的video是无法播放直播视频流的,所以需要使用原生增加的播放控件。
HTML5plus扩展的原生视频播放控件(也是uni-app的App端自带的)支持视频格式包括mp4和flv,视频传输协议支持http/https和rtmp/hls/rtsp(直播流)
-
创建视频播放控件
- uni-app模式
uni-app模式直接使用<video>组件进行播放,无需其他复杂设置。 - 5+App模式
在页面中视频播放控件需要绑定div确定位置及大小,创建视频播放控件需要传入div的id,示例如下:<!DOCTYPE HTML> <html> <head> <meta charset="utf-8"/> <meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/> <title>Hello H5+</title> <script type="text/javascript"> var video = null; // H5 plus事件处理 function plusReady(){ // 创建视频播放控件 video = new plus.video.VideoPlayer('video',{ src:'rtmp://live.hkstv.hk.lxdns.com/live/hks' }); } document.addEventListener('plusready', plusReady, false); </script> </head> <body> <br/> <div id="video" style="width:98%;height:300px;background-color:#000000;margin:auto"></div> </body> </html>
其中new plus.video.VideoPlayer()第一个参数'video'为绑定div的id值,第二个参数中的src属性值为要播放的直播视频地址,直播视频必须为rtmp协议。创建后返回视频播放控件(VideoPlayer)对象,后续可通过此对象进行操作控制。
- uni-app模式
-
播放视频流
创建视频播放控件后可通过setOptions方法更新播放控件参数,如下更新视频服务器地址:video.setOptions({src:'新的视频服务器地址'});
用户可以点击播放控件上的播放按钮进行播放,也可调用play方法进行播放:
video.play();
如果想在视频上绘制一些内容,比如滚动的聊天记录,5+App可以在上面创建一个透明webview,具体代码在Hello H5+的video示例里有;uni-app可以在上面创建一个subnvue,在HBuilderX1.9.10+版本中自带的hello uni-app - API - 界面 - 原生子窗体中也有示例。
包括防盗播的跑马灯也可以这么做。
更多API参考文档http://www.html5plus.org/doc/zh_cn/video.html#plus.video.VideoPlayer。
三方示例模板
这个是插件市场里三方开发者做的直播业务模板,开源,可以参考:http://ext.dcloud.net.cn/plugin?id=226
还有一些开发者封装了三方原生sdk,比如腾讯直播sdk,可以在插件市场获取
收起阅读 »
免费赠送前端各种学习资料
1:微信小游戏入门与实战 点击跳转
2:黑马程序员_node.js视屏教程详解(内含所有源码) 点击跳转
3:jQuery基础视频集合 点击跳转
4:黑马程序员_2018版Ajax教程精讲 点击跳转
5:黑马程序员_2018版Html5+Css3由浅入深 点击跳转
6:黑马程序员_canvas详解 点击跳转
7:黑马程序员_电商实战项目视频(含源码) 点击跳转
8:黑马程序员_ 2018移动web进阶教程 点击跳转
9:ajax详解_视屏教程 点击跳转
10:vue详解 点击跳转
11:毕向东JavaScript视频教程 点击跳转
12:黑马程序员_超全面的javaWeb视频教程点击跳转
13:黑马程序员-JavaScript-高级视频点击跳转
14:黑马程序员:reactjs精品教程视频点击跳转
15:传智播客-黑马程序员最新视频:轻松玩转微信小程序点击跳转
16:vue 2.0 入门及到实战开发点击跳转
1:微信小游戏入门与实战 点击跳转
2:黑马程序员_node.js视屏教程详解(内含所有源码) 点击跳转
3:jQuery基础视频集合 点击跳转
4:黑马程序员_2018版Ajax教程精讲 点击跳转
5:黑马程序员_2018版Html5+Css3由浅入深 点击跳转
6:黑马程序员_canvas详解 点击跳转
7:黑马程序员_电商实战项目视频(含源码) 点击跳转
8:黑马程序员_ 2018移动web进阶教程 点击跳转
9:ajax详解_视屏教程 点击跳转
10:vue详解 点击跳转
11:毕向东JavaScript视频教程 点击跳转
12:黑马程序员_超全面的javaWeb视频教程点击跳转
13:黑马程序员-JavaScript-高级视频点击跳转
14:黑马程序员:reactjs精品教程视频点击跳转
15:传智播客-黑马程序员最新视频:轻松玩转微信小程序点击跳转
16:vue 2.0 入门及到实战开发点击跳转
收起阅读 »
ios离线打包后界面包括字体变大
其实这个原因我也找了很多论坛上的帖子,
刚开始以为是不是改了配置什么的东西,
通过各个帖子来看,有说启动图片被替换后导致的,也有说各种原因 ,我觉得这个应该是没用定数的,
通过之前打包ios的sdk进行对比,
发现,还真有一张图片被替换掉了,再把先前打包的那张图片换回来 正常了
究其原因 还是各个细节没有做好,很多遗漏性的问题或者被忘记
这是这个变大的截图
这是正常的截图
首先 出现这个问题 不会是html代码和css样式的问题 很肯定
刚开始也怀疑过是ios的sdk更新了的原因
附上其他人的已解决问题:
其实这个原因我也找了很多论坛上的帖子,
刚开始以为是不是改了配置什么的东西,
通过各个帖子来看,有说启动图片被替换后导致的,也有说各种原因 ,我觉得这个应该是没用定数的,
通过之前打包ios的sdk进行对比,
发现,还真有一张图片被替换掉了,再把先前打包的那张图片换回来 正常了
究其原因 还是各个细节没有做好,很多遗漏性的问题或者被忘记
这是这个变大的截图
这是正常的截图
首先 出现这个问题 不会是html代码和css样式的问题 很肯定
刚开始也怀疑过是ios的sdk更新了的原因
附上其他人的已解决问题:
iphone6 webview中字体被放大显示,safari中查看正常没有放大
收起阅读 »
[通知]云端打包校验应用属主权限
为规范应用管理,避免appid滥用导致的广告误开等问题,自2018.06.22起新建appid,申请云端打包时会校验appid属主及协作者权限,若权限不满足,则不允许打包。
因此,若你的App是多人协作,你需要将相关同事加入协作者并赋予“云端打包”权限,否则除你之外,其它同事将无法对该App进行打包;设置协作者方法参考教程。
若App为企业应用,且是员工个人账号创建的,员工离职时,需要将该应用转让给公司账号或交接的同事账号;转让应用方法参考教程。
本次改造仅针对2018.06.22后新建的appid,适用于5+App、wap2app、uni-app类型应用;在此之前创建的应用,我们也会逐步梳理,建议开发者提前设置协作者,避免影响自己的收益或用户体验。
如依旧存在困惑,可以单独发帖详细说明情况。如需更多帮助,请发送邮件至 service@dcloud.io。
为规范应用管理,避免appid滥用导致的广告误开等问题,自2018.06.22起新建appid,申请云端打包时会校验appid属主及协作者权限,若权限不满足,则不允许打包。
因此,若你的App是多人协作,你需要将相关同事加入协作者并赋予“云端打包”权限,否则除你之外,其它同事将无法对该App进行打包;设置协作者方法参考教程。
若App为企业应用,且是员工个人账号创建的,员工离职时,需要将该应用转让给公司账号或交接的同事账号;转让应用方法参考教程。
本次改造仅针对2018.06.22后新建的appid,适用于5+App、wap2app、uni-app类型应用;在此之前创建的应用,我们也会逐步梳理,建议开发者提前设置协作者,避免影响自己的收益或用户体验。
如依旧存在困惑,可以单独发帖详细说明情况。如需更多帮助,请发送邮件至 service@dcloud.io。
收起阅读 »
hbuilder开发安卓发布APP到谷歌市场的问题汇总
分享一下在发布谷歌市场时候遇到的坑。
1.首先mui hbuilder云打包的不是8.0 而谷歌市场必须要求8.0及以上版本打包,所以得下载android studio 混合开发。
2.在混合开发中需要用官方的SDKdemo。 使用官方的SDK demo按教程进行修改。(注意: 看了一下官方的demo 得和AndroidManifest.xml文件里的包名一致。 官方离线打包的说明没特别说明这个地方,而且貌似还误导了,让和hbuilder里面的一样了。)
3.关于谷歌内购 ,还是得需要用到一个插件billingclient https://gitee.com/tjbaobao/GoogleBuillingUtil
4.然后就是安卓6.0以上的动态授权问题:用这个插件搞定 compile 'me.weyye.hipermission:library:1.0.3'
5.然后就是横竖屏幕问题,因为安卓横竖屏幕切换会自动重新加载webview,这个问题百度有详细,我们又重写不了官方sdk里面的代码,所以hbuilder这个混合开发方式怎么办,只能先锁定竖屏plus.screen.lockOrientation("portrait-primary");,然后在需要横屏的地方用样式来旋转页面90度。
分享一下在发布谷歌市场时候遇到的坑。
1.首先mui hbuilder云打包的不是8.0 而谷歌市场必须要求8.0及以上版本打包,所以得下载android studio 混合开发。
2.在混合开发中需要用官方的SDKdemo。 使用官方的SDK demo按教程进行修改。(注意: 看了一下官方的demo 得和AndroidManifest.xml文件里的包名一致。 官方离线打包的说明没特别说明这个地方,而且貌似还误导了,让和hbuilder里面的一样了。)
3.关于谷歌内购 ,还是得需要用到一个插件billingclient https://gitee.com/tjbaobao/GoogleBuillingUtil
4.然后就是安卓6.0以上的动态授权问题:用这个插件搞定 compile 'me.weyye.hipermission:library:1.0.3'
5.然后就是横竖屏幕问题,因为安卓横竖屏幕切换会自动重新加载webview,这个问题百度有详细,我们又重写不了官方sdk里面的代码,所以hbuilder这个混合开发方式怎么办,只能先锁定竖屏plus.screen.lockOrientation("portrait-primary");,然后在需要横屏的地方用样式来旋转页面90度。
收起阅读 »
开发入门篇:你会Pick小程序还是App?其实他们合体更互补!
移动互联网时代,传统行业翻身,到底该pick小程序,还是App?这成为了众多企业家和创业者的入门疑惑。实质上,我们都进入了App和小程序必须要厮杀到底的误区。那么到底,为什么说小程序和App合体更为互补呢?
App pk 小程序,开发前必须知道的事儿
- App重功能,小程序更适合于社交轻量化的尝试 。
App能够实现功能复杂、交互繁琐的重服务,而小程序则更专注以“轻”服务满足用户。
一重一轻,用户体验能达到良好的平衡。
- App适合深度用户运营,小程序则更适用于引流
小程序依靠微信助力,其前途无可限量,10亿流量成为了其快速扩张势力的极大本金。因此,不少高频需求的产品,纷纷下海做起了小程序,并且业绩可嘉。
另一方面,App虽然没有流量大树撑腰,但是从长远发展的角度来看,它能沉淀用户到平台,方便企业进行深度的用户运营。既能不断开发用户价值,又能为平台不断累积忠实用户,为后续发展打下坚实基础。
一引一收,流量层层沉淀,方可厚积薄发。
3.App使用路径短,小程序使用门槛低
App的使用路径更短,只需下载 > 安装 > 打开应用 > 使用,更方便经常打开App的用户使用习惯。并且,安卓手机用户很少会将小程序添加到桌面。
与此相比,小程序无需下载,随开随用。但是,需要先打开微信 > 搜索小程序 > 打开小程序,最后才能进行使用,从便捷度上,反而不如App。
归根结底,综合使用频次以及便捷度,一短一低,真正方便用户的才是王道。
4.App无惧中心化,小程序推广成本低
其实,企业只要萌生了做平台的想法,无非一有资源,二有人脉。早已颇有远见的电商企业又怎会坐等被平台宰割?自然是去了中心化(如淘宝天猫等),化去一切条条框框的商业枷锁,自己为自己做嫁衣,方为上策。因而,App可以说是企业打造专属平台的首选产品。
而小程序则全然不同,它有着天然的微信助力,以及背后企鹅爸爸的加持,其引流成本低廉,无需推广即可获客,深受企业方青睐。并且,小程序无广告,用户体验更好。但是,随着小程序的扩张,其商业框架势必要加重,企业仅靠小程序的确能发家,但从长远来看,为免会因腾讯捉襟见肘。
一松一紧,张弛有度,才能酝酿商业佳绩。
聊了这么多,想必大家都有一个共识。为什么我们要以不惜自伤手足的方式,去轻易地干掉App或者小程序任意一个平台呢?的确,他们各有长短,各具优势,其商业价值并非是毫无互联网试水经验者所能简单评估的。着眼企业的长远利益,想必,谁都不想把鸡蛋全放在同一个篮子中吧。毕竟,三十年河东,三十年河西,移动互联网变化如此之快,每个平台的优势都在瞬息万变,企业家应当如何抉择呢?
力谱云给出的答案是,全渠道的移动解决方案。
通过力谱云平台,即可打通App、小程序、微官网、移动网站的任督二脉,全渠道开启移动蓝海之旅,并可进行全局统筹运营,管理更轻松,成本更节省。
力谱云不做单纯的App开发,凭借着多年开发&市场经验的沉淀,我们会为每个企业,依据其市场动态以及企业需求,量身打造最适合企业的移动解决方案。并且,依靠“SaaS+PaaS”创新云计算模式,我们在性价比方面更是业内的一枝独秀。
力谱云功能强大,支持企业构建B2C、B2B、B2B2C、OMO等复杂业务平台,现已重磅推出云集分销、拼多多、生鲜/外卖配送、新渠道裂变等多种解决方案。
力谱云营销功能给力,拼团、多级分销、秒杀、满减优惠、代金券等每月不断迭代更新;更支持功能无限拓展,全面满足企业个性化开发需求。
此外,通过强大的大数据分析,企业即可精准分析用户、商品等数据,有效制定营销战略方针。
总而言之,力谱云通过全渠道获客、高效销售变现、全场景运营、精准分析和优化,为企业从研发到运营、营销、销售,开启全程护航之路。
入海互联网,选择力谱云,打造你的专属移动电商王国吧!
移动互联网时代,传统行业翻身,到底该pick小程序,还是App?这成为了众多企业家和创业者的入门疑惑。实质上,我们都进入了App和小程序必须要厮杀到底的误区。那么到底,为什么说小程序和App合体更为互补呢?
App pk 小程序,开发前必须知道的事儿
- App重功能,小程序更适合于社交轻量化的尝试 。
App能够实现功能复杂、交互繁琐的重服务,而小程序则更专注以“轻”服务满足用户。
一重一轻,用户体验能达到良好的平衡。
- App适合深度用户运营,小程序则更适用于引流
小程序依靠微信助力,其前途无可限量,10亿流量成为了其快速扩张势力的极大本金。因此,不少高频需求的产品,纷纷下海做起了小程序,并且业绩可嘉。
另一方面,App虽然没有流量大树撑腰,但是从长远发展的角度来看,它能沉淀用户到平台,方便企业进行深度的用户运营。既能不断开发用户价值,又能为平台不断累积忠实用户,为后续发展打下坚实基础。
一引一收,流量层层沉淀,方可厚积薄发。
3.App使用路径短,小程序使用门槛低
App的使用路径更短,只需下载 > 安装 > 打开应用 > 使用,更方便经常打开App的用户使用习惯。并且,安卓手机用户很少会将小程序添加到桌面。
与此相比,小程序无需下载,随开随用。但是,需要先打开微信 > 搜索小程序 > 打开小程序,最后才能进行使用,从便捷度上,反而不如App。
归根结底,综合使用频次以及便捷度,一短一低,真正方便用户的才是王道。
4.App无惧中心化,小程序推广成本低
其实,企业只要萌生了做平台的想法,无非一有资源,二有人脉。早已颇有远见的电商企业又怎会坐等被平台宰割?自然是去了中心化(如淘宝天猫等),化去一切条条框框的商业枷锁,自己为自己做嫁衣,方为上策。因而,App可以说是企业打造专属平台的首选产品。
而小程序则全然不同,它有着天然的微信助力,以及背后企鹅爸爸的加持,其引流成本低廉,无需推广即可获客,深受企业方青睐。并且,小程序无广告,用户体验更好。但是,随着小程序的扩张,其商业框架势必要加重,企业仅靠小程序的确能发家,但从长远来看,为免会因腾讯捉襟见肘。
一松一紧,张弛有度,才能酝酿商业佳绩。
聊了这么多,想必大家都有一个共识。为什么我们要以不惜自伤手足的方式,去轻易地干掉App或者小程序任意一个平台呢?的确,他们各有长短,各具优势,其商业价值并非是毫无互联网试水经验者所能简单评估的。着眼企业的长远利益,想必,谁都不想把鸡蛋全放在同一个篮子中吧。毕竟,三十年河东,三十年河西,移动互联网变化如此之快,每个平台的优势都在瞬息万变,企业家应当如何抉择呢?
力谱云给出的答案是,全渠道的移动解决方案。
通过力谱云平台,即可打通App、小程序、微官网、移动网站的任督二脉,全渠道开启移动蓝海之旅,并可进行全局统筹运营,管理更轻松,成本更节省。
力谱云不做单纯的App开发,凭借着多年开发&市场经验的沉淀,我们会为每个企业,依据其市场动态以及企业需求,量身打造最适合企业的移动解决方案。并且,依靠“SaaS+PaaS”创新云计算模式,我们在性价比方面更是业内的一枝独秀。
力谱云功能强大,支持企业构建B2C、B2B、B2B2C、OMO等复杂业务平台,现已重磅推出云集分销、拼多多、生鲜/外卖配送、新渠道裂变等多种解决方案。
力谱云营销功能给力,拼团、多级分销、秒杀、满减优惠、代金券等每月不断迭代更新;更支持功能无限拓展,全面满足企业个性化开发需求。
此外,通过强大的大数据分析,企业即可精准分析用户、商品等数据,有效制定营销战略方针。
总而言之,力谱云通过全渠道获客、高效销售变现、全场景运营、精准分析和优化,为企业从研发到运营、营销、销售,开启全程护航之路。
入海互联网,选择力谱云,打造你的专属移动电商王国吧!

分享 Android Studio 离线打包 阿里云 短视频 SDK 基础版
离线打包一些第三方的SDK, 犹如一名战士穿上铠甲,大大增强了战斗力,让你的APP 功能变得更加强大。
Android Studio 离线打包 阿里云 短视频 SDK 基础版
1.基础版: 只有录制和裁剪功能,
- 标准版:可以修改UI
- 专业版: 很复杂的功能
可以参考,阿里云SDK说明
阿里云短视频基础版
如何没有离线打包过的,可以参考,官方最新的AS 打包教程:
AS 最新离线打包教程
扫一扫下载安卓dome体验
里云的SDK包 QuSdk-RC.aar 复制到 libs/ 目录下,和 armeabi-v7a 文件夹复制到 libs/ 下里面是些os文件。
第二步:添加 阿里云 的依赖,在build.gradle ,文件 dependencies 里添加,
implementation(name: 'QuSdk-RC', ext: 'aar')
compile 'com.android.support:appcompat-v7:24.2.1'
compile 'com.android.support:design:24.2.1'
compile 'com.google.code.findbugs:jsr305:3.0.0'
compile 'com.github.bumptech.glide:glide:3.7.0'
compile 'pub.devrel:easypermissions:0.2.1'
compile 'com.squareup.okhttp3:okhttp:3.2.0'
compile 'com.github.bumptech.glide:okhttp3-integration:1.4.0@aar'
compile 'com.squareup.okio:okio:1.12.0'
compile 'com.google.code.gson:gson:2.8.0'
然后再在 在build.gradle 文件里和 dependencies 同级别 处添加
repositories {
flatDir {
dirs 'libs'
}
}
然后再在 在build.gradle 文件里android 处添加
sourceSets.main {
jni.srcDirs = []
jniLibs.srcDir "libs"
}
然后在设置AndroidManifest.xml文件,声明使用权限(必须)
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-permission android:name="android.permission.RECORD_VIDEO" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
第三步:以上权限,和SDK 的一些配置,已经配好了,下面进入写代码:
基础版的,代码很少,也简单,目前写两个java文件,一个用于初始化,别一个用于调用录制
要用视频录制,先初始化阿里云 短视频组件,
写了一个 :AliyunServer 类, 然在 dcloud_properties.xml ,services 服务项,添加一行,用于,应用打开时,就执行该文件,用于初始化阿里云 短视频组件
<service name="AliyunServer" value="com.Video.integrate.AliyunServer"/>
基础版,只需要添加这三行就可以。
package com.Video.integrate;
import android.content.Context;
import android.os.Bundle;
import com.aliyun.common.httpfinal.QupaiHttpFinal;
import io.dcloud.common.DHInterface.StandardFeature;
/**
* Created by Administrator on 2018-06-20.
*/
public class AliyunServer extends StandardFeature
{
public void onStart(Context pContext, Bundle pSavedInstanceState, String[] pRuntimeArgs) {
/**
* 如果需要在应用启动时进行初始化,可以继承这个方法,并在properties.xml文件的service节点添加扩展插件的注册即可触发onStart方法
* */
//当应用打开时,初始化,阿里SDK短视频 组件
System.loadLibrary("QuCore-ThirdParty");
System.loadLibrary("QuCore");
QupaiHttpFinal.getInstance().initOkHttpFinal();
}
}
第二步就是:AliyunVideo 类,用于调起录制页面
package com.Video.integrate;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Window;
import com.aliyun.demo.recorder.AliyunVideoRecorder;
import com.aliyun.struct.common.CropKey;
import com.aliyun.struct.common.ScaleMode;
import com.aliyun.struct.common.VideoQuality;
import com.aliyun.struct.recorder.CameraType;
import com.aliyun.struct.recorder.FlashType;
import com.aliyun.struct.snap.AliyunSnapVideoParam;
import org.json.JSONException;
import org.json.JSONObject;
public class AliyunVideo extends Activity
{
private static final int REQUEST_CODE_RECORD_VIDEO= 1002;
private int resolutionMode,ratioMode,recordMode,beautyLevel,max,min,gop,minVideoDuration,maxVideoDuration,minCropDuration,frameRate,resulutionMode;
private boolean beautyStatus,needClip,needRecord;
private CameraType cameraType;
private FlashType flashType;
private VideoQuality videoQulity;
private ScaleMode cropMode;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
Intent intent = this.getIntent();
String datajson= intent.getCharSequenceExtra("datajson").toString();
try {
JSONObject object=new JSONObject(datajson);
String _resolutionMode=object.getString("setResolutionMode");
resolutionMode=onRESOLUTION(_resolutionMode);
String _setRatioMode=object.getString("setRatioMode");
if(_setRatioMode.equals("1/1")){
ratioMode = AliyunSnapVideoParam.RATIO_MODE_1_1;
}else if(_setRatioMode.equals("3/4")){
ratioMode = AliyunSnapVideoParam.RATIO_MODE_3_4;
}else if(_setRatioMode.equals("9/16")){
ratioMode = AliyunSnapVideoParam.RATIO_MODE_9_16;
}
String _setRecordMode=object.getString("setRecordMode").trim().toLowerCase();
if(_setRecordMode.equals("auto")){
recordMode=AliyunSnapVideoParam.RECORD_MODE_AUTO;
}else if(_setRecordMode.equals("press")){
recordMode= AliyunSnapVideoParam.RECORD_MODE_PRESS;
}else if(_setRecordMode.equals("touch")){
recordMode= AliyunSnapVideoParam.RECORD_MODE_TOUCH;
}
beautyLevel=object.getInt("setBeautyLevel");
beautyStatus=object.getBoolean("setBeautyStatus");
String _cameraType=object.getString("setCameraType").trim().toLowerCase();
if(_cameraType.equals("front"))
{
cameraType=CameraType.FRONT;
// Log.i("KPPPPPPPPFGGGGGGGGG", _cameraType);
} else{cameraType=CameraType.BACK;}
String _flashType=object.getString("setFlashType").trim().toLowerCase();
if(_flashType.equals("no")){
flashType=FlashType.ON;
}else if(_flashType.equals("off")){
flashType= FlashType.OFF;
}else if(_flashType.equals("auto")){
flashType= FlashType.AUTO;
}
needClip=object.getBoolean("setNeedClip");
max=object.getInt("setMaxDuration")*1000;
min=object.getInt("setMinDuration")*1000;
String _videoQuality=object.getString("setVideoQuality").trim().toLowerCase();
if(_videoQuality.equals("ld")){
videoQulity = VideoQuality.LD;
}else if(_videoQuality.equals("sd")){
videoQulity = VideoQuality.SD;
}else if(_videoQuality.equals("hd")){
videoQulity = VideoQuality.HD;
}else if(_videoQuality.equals("ssd")){
videoQulity = VideoQuality.SSD;
}
gop=object.getInt("setGop");
minVideoDuration=object.getInt("setMinVideoDuration")*1000;
maxVideoDuration=object.getInt("setMaxVideoDuration")*1000;
minCropDuration=object.getInt("setMinCropDuration")*1000;
frameRate=object.getInt("setFrameRate");
needRecord=object.getBoolean("setNeedRecord");
String _resulutionMode=object.getString("setResulutionMode");
resulutionMode=onRESOLUTION(_resulutionMode);
String _cropMode=object.getString("setCropMode").trim().toLowerCase();
cropMode=(_cropMode.equals("cpu")?ScaleMode.PS:ScaleMode.LB);
} catch (JSONException e){
e.printStackTrace();
}
AliyunSnapVideoParam recordParam=new AliyunSnapVideoParam.Builder()
.setResolutionMode(resolutionMode) //录制 设置录制分辨率,目前支持360p,480p,540p,720p
.setRatioMode(ratioMode) //录制 设置视频比例,目前支持1:1,3:4,9:16
.setRecordMode(recordMode) //录制 设置录制模式,目前支持按录,点录和混合模式
// .setFilterList(eff_dirs) //录制 设置滤镜地址列表,具体滤镜接口接收的是一个滤镜数组
.setBeautyLevel(beautyLevel) //录制 设置美颜度
.setBeautyStatus(beautyStatus) //录制 设置美颜开关
.setCameraType(cameraType) //录制 设置前后置摄像头
.setFlashType(flashType) //录制 设置闪光灯模式
.setNeedClip(needClip) //录制 设置是否需要支持片段录制
.setMaxDuration(max) //录制 设置最大录制时长 单位毫秒
.setMinDuration(min) //录制 设置最小录制时长 单位毫秒
.setVideoQuality(videoQulity) //录制设置视频质量
.setGop(gop) //设置关键帧间隔
// .setVideoBitrate(2000) //录制设置视频码率,如果不设置则使用视频质量videoQulity参数计算出码率
.setMinVideoDuration(minVideoDuration) //裁剪 设置过滤的视频最小长度 单位毫秒
.setMaxVideoDuration(maxVideoDuration) //裁剪 设置过滤的视频最大长度 单位毫秒
.setMinCropDuration(minCropDuration) //裁剪 设置视频最小裁剪时间 单位毫秒
.setFrameRate(frameRate) //裁剪 设置帧率
.setNeedRecord(needRecord)//设置是否需要开放录制入口
.setResulutionMode(resulutionMode) //设置分辨率,目前支持360p,480p,540p,720p
.setCropMode(cropMode) //设置裁剪方式,是否使用gpu进行裁剪,不设置则默认使用cpu来裁剪
.setSortMode(AliyunSnapVideoParam.SORT_MODE_VIDEO) //设置导入相册过滤选择视频
.build();
AliyunVideoRecorder.startRecordForResult(this, REQUEST_CODE_RECORD_VIDEO, recordParam);
}
//分辨率
public int onRESOLUTION(String name)
{
name=name.trim().toLowerCase();
Integer num=0;
if(name.equals("360p"))
{ num= AliyunSnapVideoParam.RESOLUTION_360P;
}else if(name.equals("480p")){
num= AliyunSnapVideoParam.RESOLUTION_480P;
}else if(name.equals("540p")){
num= AliyunSnapVideoParam.RESOLUTION_540P;
}else if(name.equals("720p"))
{
num= AliyunSnapVideoParam.RESOLUTION_720P;
}
return num;
}
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
Intent intent=new Intent();
if(requestCode ==REQUEST_CODE_RECORD_VIDEO)
{
if(resultCode == Activity.RESULT_OK && data!= null)
{
int type = data.getIntExtra(AliyunVideoRecorder.RESULT_TYPE,0);
if(type == AliyunVideoRecorder.RESULT_TYPE_CROP) //截取视频
{
String path = data.getStringExtra(CropKey.RESULT_KEY_CROP_PATH);
intent.putExtra("resultCode","000000");
intent.putExtra("type","CROP");
intent.putExtra("path",path);
// intent.putExtra("time",data.getLongExtra(CropKey.RESULT_KEY_DURATION,0));
}else if(type == AliyunVideoRecorder.RESULT_TYPE_RECORD) //录制视频
{
String path = data.getStringExtra(AliyunVideoRecorder.OUTPUT_PATH);
intent.putExtra("resultCode","000000");
intent.putExtra("type","RECORD");
intent.putExtra("path",path);
// intent.putExtra("time",data.getLongExtra(AliyunVideoRecorder.R,0));
}
}else if(resultCode == Activity.RESULT_CANCELED)
{
intent.putExtra("resultCode","-1");
}
}
else {intent.putExtra("resultCode","-2");}
setResult(RESULT_OK,intent);
this.finish();
}
}
然后在html 页面 用JS通过 Native.js,调用原生类 ,写了一个,AliyunVideo.js 插件:
//实例化插件
var vide=new AliyunVideo(
{
setResolutionMode:"720p", //录制 设置录制分辨率,目前支持360p,480p,540p,720p
setRatioMode:"1/1", //录制 设置视频比例,目前支持1/1 ,3/4, 9/16
setRecordMode:"AUTO", //录制 设置录制模式,目前支持按录:PRESS,点录:TOUCH和混合模式:AUTO
setBeautyLevel:60, //录制 设置美颜度,1-100,比率
setBeautyStatus:true, //录制 设置美颜开关
setCameraType:"BACK", //录制 设置前后置摄像头, 后:BACK ,前:FRONT
setFlashType:"OFF", //录制 设置闪光灯模式,开:NO, 关:OFF, 自动:AUTO
setNeedClip:true, //录制 设置是否需要支持片段录制
setMaxDuration:15, //录制 设置最大录制时长 单位秒
setMinDuration:2, //录制 设置最小录制时长 单位秒
setVideoQuality:"HD", //录制设置视频质量 4个级别, 低:LD ,中:SD ,高:HD ,极高:SSD
setGop:125, //设置关键帧间隔,建议:1-300之间
setMinVideoDuration:5, //裁剪 设置过滤的视频最小长度 单位秒
setMaxVideoDuration:15, //裁剪 设置过滤的视频最大长度 单位秒
setMinCropDuration:2, //裁剪 设置视频最小裁剪时间 单位毫秒
setFrameRate:25, //裁剪 设置帧率
setNeedRecord:false, //设置是否需要开放录制入口,即选择视频的页面,多出一个录制按钮
setResulutionMode:"540p", //设置裁剪分辨率,目前支持360p,480p,540p,720p
setCropMode:"cpu" //设置裁剪方式,是否使用gpu进行裁剪,不设置则默认使用cpu来裁剪
});
// js 打开录制视频页面
vide.open(function(e)
{
if(e.code=="000000")
{
//录制视频或裁剪视频,成功后,返回视频一个地址
mui.toast("视频地址:"+e.path);
}
else if(e.code=="-1")
{ //用户取消行为
mui.toast("用户已取消");
}
});
下面是AS工程包,因官方上传限制, 不包含阿里云的SDK, 另外下载
离线打包一些第三方的SDK, 犹如一名战士穿上铠甲,大大增强了战斗力,让你的APP 功能变得更加强大。
Android Studio 离线打包 阿里云 短视频 SDK 基础版
1.基础版: 只有录制和裁剪功能,
- 标准版:可以修改UI
- 专业版: 很复杂的功能
可以参考,阿里云SDK说明
阿里云短视频基础版
如何没有离线打包过的,可以参考,官方最新的AS 打包教程:
AS 最新离线打包教程
扫一扫下载安卓dome体验
里云的SDK包 QuSdk-RC.aar 复制到 libs/ 目录下,和 armeabi-v7a 文件夹复制到 libs/ 下里面是些os文件。
第二步:添加 阿里云 的依赖,在build.gradle ,文件 dependencies 里添加,
implementation(name: 'QuSdk-RC', ext: 'aar')
compile 'com.android.support:appcompat-v7:24.2.1'
compile 'com.android.support:design:24.2.1'
compile 'com.google.code.findbugs:jsr305:3.0.0'
compile 'com.github.bumptech.glide:glide:3.7.0'
compile 'pub.devrel:easypermissions:0.2.1'
compile 'com.squareup.okhttp3:okhttp:3.2.0'
compile 'com.github.bumptech.glide:okhttp3-integration:1.4.0@aar'
compile 'com.squareup.okio:okio:1.12.0'
compile 'com.google.code.gson:gson:2.8.0'
然后再在 在build.gradle 文件里和 dependencies 同级别 处添加
repositories {
flatDir {
dirs 'libs'
}
}
然后再在 在build.gradle 文件里android 处添加
sourceSets.main {
jni.srcDirs = []
jniLibs.srcDir "libs"
}
然后在设置AndroidManifest.xml文件,声明使用权限(必须)
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-permission android:name="android.permission.RECORD_VIDEO" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
第三步:以上权限,和SDK 的一些配置,已经配好了,下面进入写代码:
基础版的,代码很少,也简单,目前写两个java文件,一个用于初始化,别一个用于调用录制
要用视频录制,先初始化阿里云 短视频组件,
写了一个 :AliyunServer 类, 然在 dcloud_properties.xml ,services 服务项,添加一行,用于,应用打开时,就执行该文件,用于初始化阿里云 短视频组件
<service name="AliyunServer" value="com.Video.integrate.AliyunServer"/>
基础版,只需要添加这三行就可以。
package com.Video.integrate;
import android.content.Context;
import android.os.Bundle;
import com.aliyun.common.httpfinal.QupaiHttpFinal;
import io.dcloud.common.DHInterface.StandardFeature;
/**
* Created by Administrator on 2018-06-20.
*/
public class AliyunServer extends StandardFeature
{
public void onStart(Context pContext, Bundle pSavedInstanceState, String[] pRuntimeArgs) {
/**
* 如果需要在应用启动时进行初始化,可以继承这个方法,并在properties.xml文件的service节点添加扩展插件的注册即可触发onStart方法
* */
//当应用打开时,初始化,阿里SDK短视频 组件
System.loadLibrary("QuCore-ThirdParty");
System.loadLibrary("QuCore");
QupaiHttpFinal.getInstance().initOkHttpFinal();
}
}
第二步就是:AliyunVideo 类,用于调起录制页面
package com.Video.integrate;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Window;
import com.aliyun.demo.recorder.AliyunVideoRecorder;
import com.aliyun.struct.common.CropKey;
import com.aliyun.struct.common.ScaleMode;
import com.aliyun.struct.common.VideoQuality;
import com.aliyun.struct.recorder.CameraType;
import com.aliyun.struct.recorder.FlashType;
import com.aliyun.struct.snap.AliyunSnapVideoParam;
import org.json.JSONException;
import org.json.JSONObject;
public class AliyunVideo extends Activity
{
private static final int REQUEST_CODE_RECORD_VIDEO= 1002;
private int resolutionMode,ratioMode,recordMode,beautyLevel,max,min,gop,minVideoDuration,maxVideoDuration,minCropDuration,frameRate,resulutionMode;
private boolean beautyStatus,needClip,needRecord;
private CameraType cameraType;
private FlashType flashType;
private VideoQuality videoQulity;
private ScaleMode cropMode;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
Intent intent = this.getIntent();
String datajson= intent.getCharSequenceExtra("datajson").toString();
try {
JSONObject object=new JSONObject(datajson);
String _resolutionMode=object.getString("setResolutionMode");
resolutionMode=onRESOLUTION(_resolutionMode);
String _setRatioMode=object.getString("setRatioMode");
if(_setRatioMode.equals("1/1")){
ratioMode = AliyunSnapVideoParam.RATIO_MODE_1_1;
}else if(_setRatioMode.equals("3/4")){
ratioMode = AliyunSnapVideoParam.RATIO_MODE_3_4;
}else if(_setRatioMode.equals("9/16")){
ratioMode = AliyunSnapVideoParam.RATIO_MODE_9_16;
}
String _setRecordMode=object.getString("setRecordMode").trim().toLowerCase();
if(_setRecordMode.equals("auto")){
recordMode=AliyunSnapVideoParam.RECORD_MODE_AUTO;
}else if(_setRecordMode.equals("press")){
recordMode= AliyunSnapVideoParam.RECORD_MODE_PRESS;
}else if(_setRecordMode.equals("touch")){
recordMode= AliyunSnapVideoParam.RECORD_MODE_TOUCH;
}
beautyLevel=object.getInt("setBeautyLevel");
beautyStatus=object.getBoolean("setBeautyStatus");
String _cameraType=object.getString("setCameraType").trim().toLowerCase();
if(_cameraType.equals("front"))
{
cameraType=CameraType.FRONT;
// Log.i("KPPPPPPPPFGGGGGGGGG", _cameraType);
} else{cameraType=CameraType.BACK;}
String _flashType=object.getString("setFlashType").trim().toLowerCase();
if(_flashType.equals("no")){
flashType=FlashType.ON;
}else if(_flashType.equals("off")){
flashType= FlashType.OFF;
}else if(_flashType.equals("auto")){
flashType= FlashType.AUTO;
}
needClip=object.getBoolean("setNeedClip");
max=object.getInt("setMaxDuration")*1000;
min=object.getInt("setMinDuration")*1000;
String _videoQuality=object.getString("setVideoQuality").trim().toLowerCase();
if(_videoQuality.equals("ld")){
videoQulity = VideoQuality.LD;
}else if(_videoQuality.equals("sd")){
videoQulity = VideoQuality.SD;
}else if(_videoQuality.equals("hd")){
videoQulity = VideoQuality.HD;
}else if(_videoQuality.equals("ssd")){
videoQulity = VideoQuality.SSD;
}
gop=object.getInt("setGop");
minVideoDuration=object.getInt("setMinVideoDuration")*1000;
maxVideoDuration=object.getInt("setMaxVideoDuration")*1000;
minCropDuration=object.getInt("setMinCropDuration")*1000;
frameRate=object.getInt("setFrameRate");
needRecord=object.getBoolean("setNeedRecord");
String _resulutionMode=object.getString("setResulutionMode");
resulutionMode=onRESOLUTION(_resulutionMode);
String _cropMode=object.getString("setCropMode").trim().toLowerCase();
cropMode=(_cropMode.equals("cpu")?ScaleMode.PS:ScaleMode.LB);
} catch (JSONException e){
e.printStackTrace();
}
AliyunSnapVideoParam recordParam=new AliyunSnapVideoParam.Builder()
.setResolutionMode(resolutionMode) //录制 设置录制分辨率,目前支持360p,480p,540p,720p
.setRatioMode(ratioMode) //录制 设置视频比例,目前支持1:1,3:4,9:16
.setRecordMode(recordMode) //录制 设置录制模式,目前支持按录,点录和混合模式
// .setFilterList(eff_dirs) //录制 设置滤镜地址列表,具体滤镜接口接收的是一个滤镜数组
.setBeautyLevel(beautyLevel) //录制 设置美颜度
.setBeautyStatus(beautyStatus) //录制 设置美颜开关
.setCameraType(cameraType) //录制 设置前后置摄像头
.setFlashType(flashType) //录制 设置闪光灯模式
.setNeedClip(needClip) //录制 设置是否需要支持片段录制
.setMaxDuration(max) //录制 设置最大录制时长 单位毫秒
.setMinDuration(min) //录制 设置最小录制时长 单位毫秒
.setVideoQuality(videoQulity) //录制设置视频质量
.setGop(gop) //设置关键帧间隔
// .setVideoBitrate(2000) //录制设置视频码率,如果不设置则使用视频质量videoQulity参数计算出码率
.setMinVideoDuration(minVideoDuration) //裁剪 设置过滤的视频最小长度 单位毫秒
.setMaxVideoDuration(maxVideoDuration) //裁剪 设置过滤的视频最大长度 单位毫秒
.setMinCropDuration(minCropDuration) //裁剪 设置视频最小裁剪时间 单位毫秒
.setFrameRate(frameRate) //裁剪 设置帧率
.setNeedRecord(needRecord)//设置是否需要开放录制入口
.setResulutionMode(resulutionMode) //设置分辨率,目前支持360p,480p,540p,720p
.setCropMode(cropMode) //设置裁剪方式,是否使用gpu进行裁剪,不设置则默认使用cpu来裁剪
.setSortMode(AliyunSnapVideoParam.SORT_MODE_VIDEO) //设置导入相册过滤选择视频
.build();
AliyunVideoRecorder.startRecordForResult(this, REQUEST_CODE_RECORD_VIDEO, recordParam);
}
//分辨率
public int onRESOLUTION(String name)
{
name=name.trim().toLowerCase();
Integer num=0;
if(name.equals("360p"))
{ num= AliyunSnapVideoParam.RESOLUTION_360P;
}else if(name.equals("480p")){
num= AliyunSnapVideoParam.RESOLUTION_480P;
}else if(name.equals("540p")){
num= AliyunSnapVideoParam.RESOLUTION_540P;
}else if(name.equals("720p"))
{
num= AliyunSnapVideoParam.RESOLUTION_720P;
}
return num;
}
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
Intent intent=new Intent();
if(requestCode ==REQUEST_CODE_RECORD_VIDEO)
{
if(resultCode == Activity.RESULT_OK && data!= null)
{
int type = data.getIntExtra(AliyunVideoRecorder.RESULT_TYPE,0);
if(type == AliyunVideoRecorder.RESULT_TYPE_CROP) //截取视频
{
String path = data.getStringExtra(CropKey.RESULT_KEY_CROP_PATH);
intent.putExtra("resultCode","000000");
intent.putExtra("type","CROP");
intent.putExtra("path",path);
// intent.putExtra("time",data.getLongExtra(CropKey.RESULT_KEY_DURATION,0));
}else if(type == AliyunVideoRecorder.RESULT_TYPE_RECORD) //录制视频
{
String path = data.getStringExtra(AliyunVideoRecorder.OUTPUT_PATH);
intent.putExtra("resultCode","000000");
intent.putExtra("type","RECORD");
intent.putExtra("path",path);
// intent.putExtra("time",data.getLongExtra(AliyunVideoRecorder.R,0));
}
}else if(resultCode == Activity.RESULT_CANCELED)
{
intent.putExtra("resultCode","-1");
}
}
else {intent.putExtra("resultCode","-2");}
setResult(RESULT_OK,intent);
this.finish();
}
}
然后在html 页面 用JS通过 Native.js,调用原生类 ,写了一个,AliyunVideo.js 插件:
//实例化插件
var vide=new AliyunVideo(
{
setResolutionMode:"720p", //录制 设置录制分辨率,目前支持360p,480p,540p,720p
setRatioMode:"1/1", //录制 设置视频比例,目前支持1/1 ,3/4, 9/16
setRecordMode:"AUTO", //录制 设置录制模式,目前支持按录:PRESS,点录:TOUCH和混合模式:AUTO
setBeautyLevel:60, //录制 设置美颜度,1-100,比率
setBeautyStatus:true, //录制 设置美颜开关
setCameraType:"BACK", //录制 设置前后置摄像头, 后:BACK ,前:FRONT
setFlashType:"OFF", //录制 设置闪光灯模式,开:NO, 关:OFF, 自动:AUTO
setNeedClip:true, //录制 设置是否需要支持片段录制
setMaxDuration:15, //录制 设置最大录制时长 单位秒
setMinDuration:2, //录制 设置最小录制时长 单位秒
setVideoQuality:"HD", //录制设置视频质量 4个级别, 低:LD ,中:SD ,高:HD ,极高:SSD
setGop:125, //设置关键帧间隔,建议:1-300之间
setMinVideoDuration:5, //裁剪 设置过滤的视频最小长度 单位秒
setMaxVideoDuration:15, //裁剪 设置过滤的视频最大长度 单位秒
setMinCropDuration:2, //裁剪 设置视频最小裁剪时间 单位毫秒
setFrameRate:25, //裁剪 设置帧率
setNeedRecord:false, //设置是否需要开放录制入口,即选择视频的页面,多出一个录制按钮
setResulutionMode:"540p", //设置裁剪分辨率,目前支持360p,480p,540p,720p
setCropMode:"cpu" //设置裁剪方式,是否使用gpu进行裁剪,不设置则默认使用cpu来裁剪
});
// js 打开录制视频页面
vide.open(function(e)
{
if(e.code=="000000")
{
//录制视频或裁剪视频,成功后,返回视频一个地址
mui.toast("视频地址:"+e.path);
}
else if(e.code=="-1")
{ //用户取消行为
mui.toast("用户已取消");
}
});
下面是AS工程包,因官方上传限制, 不包含阿里云的SDK, 另外下载
收起阅读 »
jsonp
全称 JSON with Padding,用于解决AJAX跨域问题的一种方案
JSON with Padding,这里的 Padding 指的就是包裹在 JSON 外层的回调函数,这么一来,是不是印象就非常深刻了呢。
1.jQuery的方案
$.ajax({
url: "http://xxxxxx",
dataType: 'jsonp',
jsonp: "callback",
jsonpCallback: "dosomething"
})
.done(function(res) {
console.log("success");
console.log(res);
})
.fail(function(res) {
console.log("error");
console.log(res);
});
后端关键代码(以PHP为例)
$result = "{'data':'JSONP Works'}"; // 这里省略了数据库查询等操作,直接给出返回值
$callback = $_GET['callback']; // 最好加上判空和默认值,以防拿不到参数
echo $callback."(".$result.")";
// 返回的结果
// dosomething({"data":"JSONP Works"});
实际发送出来的完整请求长这样:http://xxxxxxxx?callback=dosomething&_=14714194443853。,后面的随机字符串是jQuery加上的。
区别于常规的 AJAX 请求,这里真正需要关心的参数有以下 3 个:
1.dataType: 'jsonp',用于表示这是一个 JSONP 请求。
2.jsonp: 'callback',用于告知服务器根据这个参数获取回调函数的名称,通常约定就叫 callback。
3.jsonpCallback: 'dosomething',回调函数的名称,也是前面callback参数的值。
其中jsonpCallback参数是可以省略的,jQuery 会自动生成一个随机字符串作为函数名,推荐这么做,以减少不必要的命名工作,同时排除潜在的安全隐患。这里由于Github Page没有后台服务,我们只能指定一个名字。注意:省略jsonpCallback的同时,jsonp参数必须指明,不能为false。
$.ajax({
url: "http://xxxxxx",
dataType: 'jsonp',
jsonp: "callback"
})
// 这样会发出如下结构的请求
// http://xxxxxx?callback=jQuery31008590081461589807_1471506026601&_=1471506026602
// 可以看到 jQuery 自动创建了一个随机字符串作为 callback 参数的值
jQuery 还支持将jsonp设置为false以避免callback参数出现在请求 URL 中,但这需要前后端配合,前端必须要指定jsonpCallback的值为一个函数名,后端由于无法从请求中获取回调函数的名称,因此也必须固定使用同名的字符串进行拼接。
$.ajax({
url: "http://tonghuashuo.github.io/test/jsonp.txt",
dataType: 'jsonp',
jsonp: false,
jsonpCallback: "myCallback"
})
// 这样会发出如下结构的请求
// http://tonghuashuo.github.io/test/jsonp.txt?_=1471506026602
// 可以看到 callback 参数被隐藏了,单从 URL 上看不容易看出这是一个 JSONP 请求
// 后端也无法从请求中获取回调函数名,因此必须事先约定好回调函数名,例如大家都使用 myCallback
后台接收到该请求后会做两件事,一是照常去获取请求的资源,构造 JSON 形式的返回内容,二是根据请求 url 中的 callback 参数(由 $.ajax() 中的 jsonp 参数指定)的值,以字符串拼接的方式,构造出一个“JavaScript函数调用”的字符串,将准备返回的JSON作为实参放入括号中,由于最终返回的是纯字符串,因此和后端所用技术无关。
重要:响应内容传回前台后,jQuery会自动接管,将其中JSON的部分剥离出来传给success()和error(),在这两个函数中可以直接读取JSON的内容,换句话说,无需实现doSomething()也可以拿到数据,当然如果你还是实现了doSomething(),它会在success()之前被调用。
参考:https://tonghuashuo.github.io/blog/jsonp.html
https://segmentfault.com/q/1010000000424040
1.url 中不用指定 callback 参数。对于 jQuery 中的 jsonp 来说,callback 参数是自动添加的
2.默认情况下,jQuery 生成的 jsonp 请求中 callback 参数是形如 callback=jQuery180099599698651582_1393992892572 这种根据看似随机的名字,对应的就是 success 那个处理函数,所以一般不用特意处理。
3.如果响应内容中是写死了 callback 名的话,那么可以对 jQuery 的 jsonp 指定 callback 名,如:
jQuery.ajax({
url: 'http://api.XXX.com/603/arealist_jsonp.txt',
dataType: 'jsonp',
jsonpCallback: 'CallBack',
success: function(data) {
// do what you want
}
})
JSONP 的优缺点
JSONP 最大的优点就是兼容性非常好,其原理决定了即便在非常古老的浏览器上也能够很好的被实现。
JSONP 的主要缺点有两个,一是只能 GET 不能 POST,因为是通过<script>引用的资源,参数全都显式的放在URL里,和 AJAX 没有半毛钱关系。二是存在安全隐患,动态插入<script>标签其实就是一种脚本注入,XSS听过没?需要多留个心眼。
纯 JavaScript 实现 JSONP
利用 jQuery 我们虽然完成了 JSONP 跨域请求,但 JSONP 本质并不是 AJAX,jQuery 将其包含在 $.ajax() 误导了不少人。为了更好的理解 JSONP,我们来用纯 JavaScript 实现一遍。
// 实现回调函数,这里没有了 jQuery 的封装,必须手动指定并实现
var dosomething = function(data){
console.log(data);
};
// 提供 JSONP 服务的 URL 地址,查询字符串中加入 callback 指定回调函数
var url = "tonghuashuo.github.io/test/jsonp.txt?callback=docomething";
// 创建 <script> 标签,设置其 src 属性
var script = document.createElement('script');
script.setAttribute('src', url);
// 把 <script> 标签加入 <body> 尾部,此时调用开始。
document.getElementsByTagName('body')[0].appendChild(script);
// 因为目标 URL 是一个后台脚本,访问后会被执行,返回的 JSON 被包裹在回调函数中以字符串的形式被返回。
// 返回的字符串放入 <script> 中就成为了一个普通的函数调用,执行回调函数,返回的 JSON 数据作为实参被传给了回调函数。
AJAX 无法跨域是受到“同源政策”的限制,但是带有src属性的标签(例如<script>、<img>、<iframe>)是不受该政策限制的,因此我们可以通过向页面中动态添加<script>标签来完成对跨域资源的访问,这也是 JSONP 方案最核心的原理。
通常我们使用<script>都是引用的静态资源(主要是 js 文件),其实它也可以用来引用动态资源(php、jsp、aspx等),后台服务被访问后返回一个“JavaScript函数调用”形式的字符串,由于是字符串,因此在后台的时候不会起到任何作用,但到了前台,放入<script>标签之内,就成了一个合法的 JavaScript 函数调用,实参是我们真正需要的数据,被调用的回调函数也已经实现了,因此就会顺利的被调用。
再次强调:JSONP 不是 AJAX,了解了它的原理之后你应该已经明白这是为什么了(事实上 JSONP 的出现让 “AJAX跨域请求”变成了伪命题,跨域的过程根本就没 AJAX 什么事)。要怪就怪 jQuery,给不明真相的吃瓜群众带来了误解。当然 jQuery 这么做也不无道理,毕竟跨域的问题是在 AJAX 中遇到的,受惯性思维影响我们自然首先会从 AJAX 的角度去寻求解决方案,因此 jQuery 才把 JSONP 封装到了$.ajax()的配置项中,至于具体的实现自然还是上面提到的方法。
解决了之前的几个误区:
1.不需要用 type: 'GET',这个参数了
- jsonp: "callback",参数不能省去,jsonpCallback: "dosomething"参数可以省去
- jsonp本质上不是ajax请求
- 在jq中jsonp请求的响应内容传回前台后,jQuery会自动接管,将其中JSON的部分剥离出来传给success()和error()
还有这种返回类型... dataType: 'html',
全称 JSON with Padding,用于解决AJAX跨域问题的一种方案
JSON with Padding,这里的 Padding 指的就是包裹在 JSON 外层的回调函数,这么一来,是不是印象就非常深刻了呢。
1.jQuery的方案
$.ajax({
url: "http://xxxxxx",
dataType: 'jsonp',
jsonp: "callback",
jsonpCallback: "dosomething"
})
.done(function(res) {
console.log("success");
console.log(res);
})
.fail(function(res) {
console.log("error");
console.log(res);
});
后端关键代码(以PHP为例)
$result = "{'data':'JSONP Works'}"; // 这里省略了数据库查询等操作,直接给出返回值
$callback = $_GET['callback']; // 最好加上判空和默认值,以防拿不到参数
echo $callback."(".$result.")";
// 返回的结果
// dosomething({"data":"JSONP Works"});
实际发送出来的完整请求长这样:http://xxxxxxxx?callback=dosomething&_=14714194443853。,后面的随机字符串是jQuery加上的。
区别于常规的 AJAX 请求,这里真正需要关心的参数有以下 3 个:
1.dataType: 'jsonp',用于表示这是一个 JSONP 请求。
2.jsonp: 'callback',用于告知服务器根据这个参数获取回调函数的名称,通常约定就叫 callback。
3.jsonpCallback: 'dosomething',回调函数的名称,也是前面callback参数的值。
其中jsonpCallback参数是可以省略的,jQuery 会自动生成一个随机字符串作为函数名,推荐这么做,以减少不必要的命名工作,同时排除潜在的安全隐患。这里由于Github Page没有后台服务,我们只能指定一个名字。注意:省略jsonpCallback的同时,jsonp参数必须指明,不能为false。
$.ajax({
url: "http://xxxxxx",
dataType: 'jsonp',
jsonp: "callback"
})
// 这样会发出如下结构的请求
// http://xxxxxx?callback=jQuery31008590081461589807_1471506026601&_=1471506026602
// 可以看到 jQuery 自动创建了一个随机字符串作为 callback 参数的值
jQuery 还支持将jsonp设置为false以避免callback参数出现在请求 URL 中,但这需要前后端配合,前端必须要指定jsonpCallback的值为一个函数名,后端由于无法从请求中获取回调函数的名称,因此也必须固定使用同名的字符串进行拼接。
$.ajax({
url: "http://tonghuashuo.github.io/test/jsonp.txt",
dataType: 'jsonp',
jsonp: false,
jsonpCallback: "myCallback"
})
// 这样会发出如下结构的请求
// http://tonghuashuo.github.io/test/jsonp.txt?_=1471506026602
// 可以看到 callback 参数被隐藏了,单从 URL 上看不容易看出这是一个 JSONP 请求
// 后端也无法从请求中获取回调函数名,因此必须事先约定好回调函数名,例如大家都使用 myCallback
后台接收到该请求后会做两件事,一是照常去获取请求的资源,构造 JSON 形式的返回内容,二是根据请求 url 中的 callback 参数(由 $.ajax() 中的 jsonp 参数指定)的值,以字符串拼接的方式,构造出一个“JavaScript函数调用”的字符串,将准备返回的JSON作为实参放入括号中,由于最终返回的是纯字符串,因此和后端所用技术无关。
重要:响应内容传回前台后,jQuery会自动接管,将其中JSON的部分剥离出来传给success()和error(),在这两个函数中可以直接读取JSON的内容,换句话说,无需实现doSomething()也可以拿到数据,当然如果你还是实现了doSomething(),它会在success()之前被调用。
参考:https://tonghuashuo.github.io/blog/jsonp.html
https://segmentfault.com/q/1010000000424040
1.url 中不用指定 callback 参数。对于 jQuery 中的 jsonp 来说,callback 参数是自动添加的
2.默认情况下,jQuery 生成的 jsonp 请求中 callback 参数是形如 callback=jQuery180099599698651582_1393992892572 这种根据看似随机的名字,对应的就是 success 那个处理函数,所以一般不用特意处理。
3.如果响应内容中是写死了 callback 名的话,那么可以对 jQuery 的 jsonp 指定 callback 名,如:
jQuery.ajax({
url: 'http://api.XXX.com/603/arealist_jsonp.txt',
dataType: 'jsonp',
jsonpCallback: 'CallBack',
success: function(data) {
// do what you want
}
})
JSONP 的优缺点
JSONP 最大的优点就是兼容性非常好,其原理决定了即便在非常古老的浏览器上也能够很好的被实现。
JSONP 的主要缺点有两个,一是只能 GET 不能 POST,因为是通过<script>引用的资源,参数全都显式的放在URL里,和 AJAX 没有半毛钱关系。二是存在安全隐患,动态插入<script>标签其实就是一种脚本注入,XSS听过没?需要多留个心眼。
纯 JavaScript 实现 JSONP
利用 jQuery 我们虽然完成了 JSONP 跨域请求,但 JSONP 本质并不是 AJAX,jQuery 将其包含在 $.ajax() 误导了不少人。为了更好的理解 JSONP,我们来用纯 JavaScript 实现一遍。
// 实现回调函数,这里没有了 jQuery 的封装,必须手动指定并实现
var dosomething = function(data){
console.log(data);
};
// 提供 JSONP 服务的 URL 地址,查询字符串中加入 callback 指定回调函数
var url = "tonghuashuo.github.io/test/jsonp.txt?callback=docomething";
// 创建 <script> 标签,设置其 src 属性
var script = document.createElement('script');
script.setAttribute('src', url);
// 把 <script> 标签加入 <body> 尾部,此时调用开始。
document.getElementsByTagName('body')[0].appendChild(script);
// 因为目标 URL 是一个后台脚本,访问后会被执行,返回的 JSON 被包裹在回调函数中以字符串的形式被返回。
// 返回的字符串放入 <script> 中就成为了一个普通的函数调用,执行回调函数,返回的 JSON 数据作为实参被传给了回调函数。
AJAX 无法跨域是受到“同源政策”的限制,但是带有src属性的标签(例如<script>、<img>、<iframe>)是不受该政策限制的,因此我们可以通过向页面中动态添加<script>标签来完成对跨域资源的访问,这也是 JSONP 方案最核心的原理。
通常我们使用<script>都是引用的静态资源(主要是 js 文件),其实它也可以用来引用动态资源(php、jsp、aspx等),后台服务被访问后返回一个“JavaScript函数调用”形式的字符串,由于是字符串,因此在后台的时候不会起到任何作用,但到了前台,放入<script>标签之内,就成了一个合法的 JavaScript 函数调用,实参是我们真正需要的数据,被调用的回调函数也已经实现了,因此就会顺利的被调用。
再次强调:JSONP 不是 AJAX,了解了它的原理之后你应该已经明白这是为什么了(事实上 JSONP 的出现让 “AJAX跨域请求”变成了伪命题,跨域的过程根本就没 AJAX 什么事)。要怪就怪 jQuery,给不明真相的吃瓜群众带来了误解。当然 jQuery 这么做也不无道理,毕竟跨域的问题是在 AJAX 中遇到的,受惯性思维影响我们自然首先会从 AJAX 的角度去寻求解决方案,因此 jQuery 才把 JSONP 封装到了$.ajax()的配置项中,至于具体的实现自然还是上面提到的方法。
解决了之前的几个误区:
1.不需要用 type: 'GET',这个参数了
- jsonp: "callback",参数不能省去,jsonpCallback: "dosomething"参数可以省去
- jsonp本质上不是ajax请求
- 在jq中jsonp请求的响应内容传回前台后,jQuery会自动接管,将其中JSON的部分剥离出来传给success()和error()
还有这种返回类型... dataType: 'html',
收起阅读 »
支付宝及微信支付填坑记
亲测,官网上下载的都是坑,付费的请联系我QQ/微信:826096331
1.商户平台已经开通微信支付功能。
-
使用自有证书打包,且生成签名与微信开放平台登记应用中的包名和签名一致。
-
调用微信统一下单接口返回参数正常,prepayid正常返回(其中sign签名我自己用官方的签名生成工具调试过,生成后是一样的)
-
manifest.json中配置了微信分享,微信支付,其中微信分享正常
-
测试支付的时候一直都是打包测试
-
真机运行,打包后安装的,还有微信客户端全部重装过并且清理过缓存
-
mui版本3.3.0(不知道是不是版本的问题)
以上的方法我全部试过了,但是一次都没有吊起过支付,全部返回-1,不知道该怎么进行下去了。。。。
最后终于搞定了
微信请参考下这里:http://www.erdangjiade.com/php/2750.html
支付宝请参考下这里:[](亲测,官网上下载的都是坑,付费的请联系我QQ/微信:826096331 微信请参考下这里:http://www.erdangjiade.com/php/2750.html
亲测,官网上下载的都是坑,付费的请联系我QQ/微信:826096331
1.商户平台已经开通微信支付功能。
-
使用自有证书打包,且生成签名与微信开放平台登记应用中的包名和签名一致。
-
调用微信统一下单接口返回参数正常,prepayid正常返回(其中sign签名我自己用官方的签名生成工具调试过,生成后是一样的)
-
manifest.json中配置了微信分享,微信支付,其中微信分享正常
-
测试支付的时候一直都是打包测试
-
真机运行,打包后安装的,还有微信客户端全部重装过并且清理过缓存
-
mui版本3.3.0(不知道是不是版本的问题)
以上的方法我全部试过了,但是一次都没有吊起过支付,全部返回-1,不知道该怎么进行下去了。。。。
最后终于搞定了
微信请参考下这里:http://www.erdangjiade.com/php/2750.html
支付宝请参考下这里:[](亲测,官网上下载的都是坑,付费的请联系我QQ/微信:826096331 微信请参考下这里:http://www.erdangjiade.com/php/2750.html

pdf.js使用总结
ps:文中图片显示的浏览效果不佳是因为PDF文件没有按照原始尺寸大小显示,最后一张图是按原始大小显示的。
由于最新有个功能需求为浏览文档,而其中一种文档格式就是PDF,怎么查看PDF文件呢?网上查了相关资料,经过综合考虑认为集成tbs或psdf.js是比较好的实现方式。tbs只支持Android,而且需要离线打包,暂时放下。在此先记录pdf.js的使用:
pdf.js地址:pdf.js
如何下载pdf.js,github里有详细的介绍,并且提供了一些使用demo。不过demo都是需要配合服务器,可能是因为开发者的本意是做PDF的在线浏览。而今天要记录的是在不使用自己的服务器的情况下,用HBuilder如何使用pdf.js。
总共有3种使用方式:
1.下载pdf.js到本地
将从GitHub下载好的pdf.js项目build目录下的generic目录及其目录下所有文件拷贝到自己的项目中
将目录名'generic'改为'pdfjs'(为何要改为psdjs,这和pdf.js这个js文件中的引用有关,看源码便知),目录结构和所含文件如图所示。
mui.openWindow({
url: 'viewer.html路径?PDF文件路径',
// 本地PDF文件url示例:'_www/pdfjs/web/viewer.html?file=file:///storage/emulated/0/xxx.pdf'
id: 'pdf_preview',
show: {
duration: 300
}
}
使用如上代码并可浏览PDF文件了,其中viewer.html就是浏览界面(由demo提供),如要添加按back键返回功能,引入mui.js便可。界面也可以根据自己的需求进行修改。
优点:无网络环境下也可正常浏览本地文件,速度相对其他两种较快
缺点:插件体积有点大
2.使用mozilla部署在github pages上的Viewer
mui.openWindow({
url:'http://mozilla.github.io/pdf.js/web/viewer.html?PDF文件路径',
// 网络PDF文件url示例:'http://mozilla.github.io/pdf.js/web/viewer.html?http://cdn.mozilla.net/pdfjs/tracemonkey.pdf'
id: 'pdf1',
show: {
duration: 300
}
})
使用如上代码并可浏览PDF文件了,其中viewer.html就是浏览界面(由demo提供),界面无法修改。
优点:无需下载插件,便可直接使用
缺点:无法浏览本地文件,需要网络,网络文件较大时加载慢,浏览界面无回退功能(用双webview可实现回退)、无法修改,会有跨域问题
3.自定义预览界面,pdf.js使用cdn的方式导入
mui.openWindow({
url: '自定义HTML路径?pdf路径',
// 本地PDF文件url示例:'_www/pdfjs/index.html?file:///storage/emulated/0/tbs.pdf'
// 网络PDF文件url示例:'_www/pdfjs/index.html?http://cdn.mozilla.net/pdfjs/tracemonkey.pdf'
id: 'pdf3',
show: {
duration: 300
}
})
使用如上代码便可浏览PDF文件了
优点:无需下载插件,使用简单,
缺点:需要网络
4.把pdf.js部署到服务端
和第3种方式类似,区别在于需要自己去部署服务器,之后的使用方法一样。
问题1:在直接实现预览的时候遇到显示模糊的问题,通过增大scale系数解决
var viewport = page.getViewport(2.0);//设置为2.0
问题2:pdf内容显示不完整,通过设置cMapUrl和cMapPacked解决
PDFJS.cMapUrl = 'https://unpkg.com/pdfjs-dist@1.9.426/cmaps/';
PDFJS.cMapPacked = true;
实际大小显示效果(横屏):
demo在附件
ps:文中图片显示的浏览效果不佳是因为PDF文件没有按照原始尺寸大小显示,最后一张图是按原始大小显示的。
由于最新有个功能需求为浏览文档,而其中一种文档格式就是PDF,怎么查看PDF文件呢?网上查了相关资料,经过综合考虑认为集成tbs或psdf.js是比较好的实现方式。tbs只支持Android,而且需要离线打包,暂时放下。在此先记录pdf.js的使用:
pdf.js地址:pdf.js
如何下载pdf.js,github里有详细的介绍,并且提供了一些使用demo。不过demo都是需要配合服务器,可能是因为开发者的本意是做PDF的在线浏览。而今天要记录的是在不使用自己的服务器的情况下,用HBuilder如何使用pdf.js。
总共有3种使用方式:
1.下载pdf.js到本地
将从GitHub下载好的pdf.js项目build目录下的generic目录及其目录下所有文件拷贝到自己的项目中
将目录名'generic'改为'pdfjs'(为何要改为psdjs,这和pdf.js这个js文件中的引用有关,看源码便知),目录结构和所含文件如图所示。
mui.openWindow({
url: 'viewer.html路径?PDF文件路径',
// 本地PDF文件url示例:'_www/pdfjs/web/viewer.html?file=file:///storage/emulated/0/xxx.pdf'
id: 'pdf_preview',
show: {
duration: 300
}
}
使用如上代码并可浏览PDF文件了,其中viewer.html就是浏览界面(由demo提供),如要添加按back键返回功能,引入mui.js便可。界面也可以根据自己的需求进行修改。
优点:无网络环境下也可正常浏览本地文件,速度相对其他两种较快
缺点:插件体积有点大
2.使用mozilla部署在github pages上的Viewer
mui.openWindow({
url:'http://mozilla.github.io/pdf.js/web/viewer.html?PDF文件路径',
// 网络PDF文件url示例:'http://mozilla.github.io/pdf.js/web/viewer.html?http://cdn.mozilla.net/pdfjs/tracemonkey.pdf'
id: 'pdf1',
show: {
duration: 300
}
})
使用如上代码并可浏览PDF文件了,其中viewer.html就是浏览界面(由demo提供),界面无法修改。
优点:无需下载插件,便可直接使用
缺点:无法浏览本地文件,需要网络,网络文件较大时加载慢,浏览界面无回退功能(用双webview可实现回退)、无法修改,会有跨域问题
3.自定义预览界面,pdf.js使用cdn的方式导入
mui.openWindow({
url: '自定义HTML路径?pdf路径',
// 本地PDF文件url示例:'_www/pdfjs/index.html?file:///storage/emulated/0/tbs.pdf'
// 网络PDF文件url示例:'_www/pdfjs/index.html?http://cdn.mozilla.net/pdfjs/tracemonkey.pdf'
id: 'pdf3',
show: {
duration: 300
}
})
使用如上代码便可浏览PDF文件了
优点:无需下载插件,使用简单,
缺点:需要网络
4.把pdf.js部署到服务端
和第3种方式类似,区别在于需要自己去部署服务器,之后的使用方法一样。
问题1:在直接实现预览的时候遇到显示模糊的问题,通过增大scale系数解决
var viewport = page.getViewport(2.0);//设置为2.0
问题2:pdf内容显示不完整,通过设置cMapUrl和cMapPacked解决
PDFJS.cMapUrl = 'https://unpkg.com/pdfjs-dist@1.9.426/cmaps/';
PDFJS.cMapPacked = true;
实际大小显示效果(横屏):
demo在附件
收起阅读 »