HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

uniapp 混合开发 Cannot read property 'onUniNViewMessage' of undefined

uniapp

uniapp 混合开发 Cannot read property 'onUniNViewMessage' of undefined

看报错原因

解决地址

https://blog.csdn.net/qq_29556507/article/details/86519401

继续阅读 »

uniapp 混合开发 Cannot read property 'onUniNViewMessage' of undefined

看报错原因

解决地址

https://blog.csdn.net/qq_29556507/article/details/86519401

收起阅读 »

uni-app 生成二维码

fork 了 qrcode, 几行代码简单粗暴画出了二维码
https://github.com/guillaume-lin/qrcodejs/blob/master/README.md

fork 了 qrcode, 几行代码简单粗暴画出了二维码
https://github.com/guillaume-lin/qrcodejs/blob/master/README.md

离线打包获取不到clientid和QQ授权、分享闪退问题

App离线打包

创建安卓应用的时候targetSdkVersion默认是28。导致部分安卓手机获取不到clientid,QQ授权分享闪退,改成21就可以了。

创建安卓应用的时候targetSdkVersion默认是28。导致部分安卓手机获取不到clientid,QQ授权分享闪退,改成21就可以了。

一个简单5+录音和播放音频分享

声音

少废话,直接上代码

    <body>  
        <button id="start" type="button">录音</button>  

        <button type="button" id="stop">停止</button>  

        <div id="data-info">  
            <button type="button" id="play">开始播放</button>  

            <button type="button" id="pause-audio">暂停播放</button>  

            <button type="button" id="continue">继续播放</button>  
        </div>  
    </body>  
    <script type="text/javascript">  
        var audio_src = null;  
        var p = null;  
        mui.plusReady(function(){  
            var start = document.getElementById('start');  
            var stop = document.getElementById('stop');  
            var play = document.getElementById('play');           
            var pause = document.getElementById('pause-audio');     //暂停播放  
            var cont_inue = document.getElementById('continue');    //继续播放  
            play.addEventListener('tap',function(){  
                p = plus.audio.createPlayer(audio_src);  
                p.play( function () {  
                    alert( "Audio play success!" );  
                }, function ( e ) {  
                    alert( "Audio play failed: " + e.message );  
                } );  
            });  
            //暂停播放  
            pause.addEventListener('tap',function(){  
                p.pause();  
            });  
            //继续播放  
            cont_inue.addEventListener('tap',function(){  
                p.resume();  
            })  
            var r = plus.audio.getRecorder();   
            start.addEventListener('tap',function(){  
                // 录音操作  
                if ( r == null ) {  
                    alert( "Device not ready!" );  
                        return;   
                }    
                r.record({filename:'_doc/audio/',format:'mp3',}, function(p){    
                    console.log('录音完成:'+p);    

                    audio_src = p;  
                }, function(e){    
                    console.log('录音失败:'+e.message);    
                });    
            });  
            stop.addEventListener('tap',function(){  
                r.stop();  
            })  
        });  
    </script>

希望对新手不懂的有帮助,交流Q群:228206998

继续阅读 »

少废话,直接上代码

    <body>  
        <button id="start" type="button">录音</button>  

        <button type="button" id="stop">停止</button>  

        <div id="data-info">  
            <button type="button" id="play">开始播放</button>  

            <button type="button" id="pause-audio">暂停播放</button>  

            <button type="button" id="continue">继续播放</button>  
        </div>  
    </body>  
    <script type="text/javascript">  
        var audio_src = null;  
        var p = null;  
        mui.plusReady(function(){  
            var start = document.getElementById('start');  
            var stop = document.getElementById('stop');  
            var play = document.getElementById('play');           
            var pause = document.getElementById('pause-audio');     //暂停播放  
            var cont_inue = document.getElementById('continue');    //继续播放  
            play.addEventListener('tap',function(){  
                p = plus.audio.createPlayer(audio_src);  
                p.play( function () {  
                    alert( "Audio play success!" );  
                }, function ( e ) {  
                    alert( "Audio play failed: " + e.message );  
                } );  
            });  
            //暂停播放  
            pause.addEventListener('tap',function(){  
                p.pause();  
            });  
            //继续播放  
            cont_inue.addEventListener('tap',function(){  
                p.resume();  
            })  
            var r = plus.audio.getRecorder();   
            start.addEventListener('tap',function(){  
                // 录音操作  
                if ( r == null ) {  
                    alert( "Device not ready!" );  
                        return;   
                }    
                r.record({filename:'_doc/audio/',format:'mp3',}, function(p){    
                    console.log('录音完成:'+p);    

                    audio_src = p;  
                }, function(e){    
                    console.log('录音失败:'+e.message);    
                });    
            });  
            stop.addEventListener('tap',function(){  
                r.stop();  
            })  
        });  
    </script>

希望对新手不懂的有帮助,交流Q群:228206998

收起阅读 »

微信公众号推送消息 怎么不限制?

微信公众平台>订阅号每天只能发1次,服务号1个月能发4次,每天次数有限如何破解

微号帮功能实现48小时不限制推送、模板消息不限制群发

print('{@nickname}参数替换粉丝昵称')

48小时每天多次推送

当粉丝和公众号发生互动时,公众号会将信号推送给开发者,开发者可以在48小时内推送消息给粉丝,以达到不限制次数推送信息给粉丝,公众号互动操作有粉丝发送信息给公众号、

粉丝点击公众号菜单(仅有点击推事件、扫码推事件、扫码推事件且弹出“消息接收中”提示框这3种菜单情况才行)、关注公众号、扫描公众号二维码、在公众号支付成功、粉丝维权

模板消息每天多次群发

公众号模板消息用于公众号向粉丝发送重要的服务通知,只能用于符合其要求的服务场景中,如服务预定通知,商品购买成功通知等,群发内容有限制,不能 影响粉丝。当前每个账号的模板消息的日调用上限为10万次,单个模板没有特殊限制。

继续阅读 »

微信公众平台>订阅号每天只能发1次,服务号1个月能发4次,每天次数有限如何破解

微号帮功能实现48小时不限制推送、模板消息不限制群发

print('{@nickname}参数替换粉丝昵称')

48小时每天多次推送

当粉丝和公众号发生互动时,公众号会将信号推送给开发者,开发者可以在48小时内推送消息给粉丝,以达到不限制次数推送信息给粉丝,公众号互动操作有粉丝发送信息给公众号、

粉丝点击公众号菜单(仅有点击推事件、扫码推事件、扫码推事件且弹出“消息接收中”提示框这3种菜单情况才行)、关注公众号、扫描公众号二维码、在公众号支付成功、粉丝维权

模板消息每天多次群发

公众号模板消息用于公众号向粉丝发送重要的服务通知,只能用于符合其要求的服务场景中,如服务预定通知,商品购买成功通知等,群发内容有限制,不能 影响粉丝。当前每个账号的模板消息的日调用上限为10万次,单个模板没有特殊限制。

收起阅读 »

Android 9.0 http无法访问网络问题或者无法调用接口

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_29634351/article/details/86654535

*最近用户报来一个投诉,说app登录不上去了,我用我8.0的手机测试了一下,明显可以登录,后面得知用户的系统是9.0系统```javascript


1  
原来9.0系统已经默认不支持http请求了,谷歌默认要求链接是加密链接了,要解决这个问题有几种方案,第一个是把http改成https,这个要让后台更改  

还有一个就是把targetSdkVersion 改成27或者以下。  

还有一个方案就是在res目录添加一个xml文件夹,新建一个xml  

编写:  

<?xml version="1.0" encoding="utf-8"?>  

<network-security-config>  
    <base-config cleartextTrafficPermitted="true" />  
</network-security-config>  
1  
2  
3  
4  
5  
在AndroidManifest.xml清单文件上加入  

更改之后,成功解决问题!  
---------------------   
作者:肖旺银   
来源:CSDN   
原文:https://blog.csdn.net/qq_29634351/article/details/86654535   
版权声明:本文为博主原创文章,转载请附上博文链接!  

https://blog.csdn.net/qq_29634351/article/details/86654535
继续阅读 »

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_29634351/article/details/86654535

*最近用户报来一个投诉,说app登录不上去了,我用我8.0的手机测试了一下,明显可以登录,后面得知用户的系统是9.0系统```javascript


1  
原来9.0系统已经默认不支持http请求了,谷歌默认要求链接是加密链接了,要解决这个问题有几种方案,第一个是把http改成https,这个要让后台更改  

还有一个就是把targetSdkVersion 改成27或者以下。  

还有一个方案就是在res目录添加一个xml文件夹,新建一个xml  

编写:  

<?xml version="1.0" encoding="utf-8"?>  

<network-security-config>  
    <base-config cleartextTrafficPermitted="true" />  
</network-security-config>  
1  
2  
3  
4  
5  
在AndroidManifest.xml清单文件上加入  

更改之后,成功解决问题!  
---------------------   
作者:肖旺银   
来源:CSDN   
原文:https://blog.csdn.net/qq_29634351/article/details/86654535   
版权声明:本文为博主原创文章,转载请附上博文链接!  

https://blog.csdn.net/qq_29634351/article/details/86654535
收起阅读 »

纯JS 打造HTML5+APP 专属 VIDEO 视频播放器,支持记忆续播 和 缓冲进度条 ,音量调节和亮度调节,支持 Android/ios

5+App开发

基础开发工具: HBuilder X

纯JS改写 video 支持 Android / IOS 播放。

支持播放视频格式:.mp4 .webm .m3u8 .mpd .flv

基础功能:

 支持: 左右滑动快进退、缓冲进度条、记忆续播、 上下视频按键播放 ,假全屏、强制横屏全屏,音量调节和亮度调节,  支持自由修改样式

5+APP为什么要使用HTML5 视频播放器?,主要为了更方便在视频表层添加任何图标或物品也方便对播放器样式改造,进行相关操作,相对原生视频播放器,要在视频层添加图标就困难多了。

http://www.html5-app.com/uploads/file/20190307/20190307015130536845.jpg

http://www.html5-app.com/uploads/file/20190307/20190307172355597386.gif

http://www.html5-app.com/uploads/file/20190307/20190307172436572807.png

扫一扫下载 安卓 DEMO 示例 体验, 或者电脑下载

http://www.html5-app.com/uploads/file/20190308/20190308053247332872.jpg

目前支持两种全屏模式:1. 假全屏-强出视频播放框保持竖屏,2. 强制横屏-就是通常说的全屏,强制横屏播放。

http://www.html5-app.com/uploads/file/20190307/20190307021341598893.jpg

如何使用:

  1. 引入视频的样式
<link href="videoStyleBlue.css" rel="stylesheet"/>
  1. 引入相关3个必须的JS 文件

    <script src="js/mui.min.js"></script> //MUI 框架  
    <script src="js/mediaeplayer.js"></script> // 支持视频播放优化插件  
    <script src="js/AppH5Video.js"></script> //视频插件,控制各项操作
  2. 添加一个video 标签在所需的位置上

    <video id="player" style="max-width:100%;display: none;"   preload="none"  controls playsinline webkit-playsinline>
  3. 初始化视频插件

    var player=new AppH5Video("player",{}); 

插件参数

autoplay: 是否自动播放视频,默认: fasle
showfull : 是否显示全屏按钮,默认: true
fakefull : 是否开启假全屏模式 ,默认: false
loop : 是否循环媒体,默认: false
back : 是否显示返回键,默认: true
drag: 是否开启左右滑动快进后退功能,默认: true

详情内容浏览:
http://www.html5-app.com/show/115

继续阅读 »

基础开发工具: HBuilder X

纯JS改写 video 支持 Android / IOS 播放。

支持播放视频格式:.mp4 .webm .m3u8 .mpd .flv

基础功能:

 支持: 左右滑动快进退、缓冲进度条、记忆续播、 上下视频按键播放 ,假全屏、强制横屏全屏,音量调节和亮度调节,  支持自由修改样式

5+APP为什么要使用HTML5 视频播放器?,主要为了更方便在视频表层添加任何图标或物品也方便对播放器样式改造,进行相关操作,相对原生视频播放器,要在视频层添加图标就困难多了。

http://www.html5-app.com/uploads/file/20190307/20190307015130536845.jpg

http://www.html5-app.com/uploads/file/20190307/20190307172355597386.gif

http://www.html5-app.com/uploads/file/20190307/20190307172436572807.png

扫一扫下载 安卓 DEMO 示例 体验, 或者电脑下载

http://www.html5-app.com/uploads/file/20190308/20190308053247332872.jpg

目前支持两种全屏模式:1. 假全屏-强出视频播放框保持竖屏,2. 强制横屏-就是通常说的全屏,强制横屏播放。

http://www.html5-app.com/uploads/file/20190307/20190307021341598893.jpg

如何使用:

  1. 引入视频的样式
<link href="videoStyleBlue.css" rel="stylesheet"/>
  1. 引入相关3个必须的JS 文件

    <script src="js/mui.min.js"></script> //MUI 框架  
    <script src="js/mediaeplayer.js"></script> // 支持视频播放优化插件  
    <script src="js/AppH5Video.js"></script> //视频插件,控制各项操作
  2. 添加一个video 标签在所需的位置上

    <video id="player" style="max-width:100%;display: none;"   preload="none"  controls playsinline webkit-playsinline>
  3. 初始化视频插件

    var player=new AppH5Video("player",{}); 

插件参数

autoplay: 是否自动播放视频,默认: fasle
showfull : 是否显示全屏按钮,默认: true
fakefull : 是否开启假全屏模式 ,默认: false
loop : 是否循环媒体,默认: false
back : 是否显示返回键,默认: true
drag: 是否开启左右滑动快进后退功能,默认: true

详情内容浏览:
http://www.html5-app.com/show/115

收起阅读 »

如何在多多客应用商店发布一个应用?

百度小程序 支付宝小程序 微信小程序 小程序

1.申请成为开发者 申请链接 http://p5a4msdozpe55dze.mikecrm.com/BldTCuQ

2.多多客(doodooke.com)应用商店进入开发者-管理应用-模块管理,创建模块,输入模块名,介绍,是否加密等。

3.打开终端,执行命令npm login --registry http://registry.doodooke.com

4.创建模块,执行命令npm init

5.上传模块,进入创建的模块目录,执行命令npm publish --registry http://registry.doodooke.com,提示如下即上传完成

6.查看模块,上传完成之后,进入开发者-管理应用-模块管理

7.进入开发者-管理应用-应用管理-版本管理,点击发布新版本,选择相应的模块发布,通过审核即可。

继续阅读 »

1.申请成为开发者 申请链接 http://p5a4msdozpe55dze.mikecrm.com/BldTCuQ

2.多多客(doodooke.com)应用商店进入开发者-管理应用-模块管理,创建模块,输入模块名,介绍,是否加密等。

3.打开终端,执行命令npm login --registry http://registry.doodooke.com

4.创建模块,执行命令npm init

5.上传模块,进入创建的模块目录,执行命令npm publish --registry http://registry.doodooke.com,提示如下即上传完成

6.查看模块,上传完成之后,进入开发者-管理应用-模块管理

7.进入开发者-管理应用-应用管理-版本管理,点击发布新版本,选择相应的模块发布,通过审核即可。

收起阅读 »

uni-app 资源在线升级/热更新

升级 wgt uniapp 热更新

官方已发布APP升级中心,支持原生APP整包升级和wgt资源包升级。详见https://uniapp.dcloud.io/uniCloud/upgrade-center

======如下是官方APP升级中心发布之前的文章,供老用户参考============

注:本文为前端代码资源热更新。如果是整包升级,另见文档https://ask.dcloud.net.cn/article/34972

HBuilderX 1.6.5 起,uni-app 支持生成 App 资源升级包。

生成 App 资源升级包

修改版本号

首先,更新 manifest.json 中的版本号。
比如之前是 1.0.0,那么新版本应该是 1.0.1 或 1.1.0 这样。

发行

然后,在 HBuilderX 中生成升级包(wgt)。
菜单->发行->原生App-制作移动App资源升级包

生成结束会在控制台告知升级包的输出位置。

安装资源升级包

应用的升级需要服务端与客户端配合完成,下面以本地测试过程中的操作举例说明:

存放资源

将 %appid%.wgt 文件存放在服务器的 static 目录下,即 http://www.example.com/static/UNI832D722.wgt。

服务端接口

约定检测升级的接口,地址为:http://www.example.com/update/

传入参数

参数名 类型 默认值 说明
name String '' 客户端读取到的应用名称,定义这个参数可以方便多个应用复用接口。
version String '' 客户端读取到的版本号信息

返回参数

参数名 类型 默认值 说明
update Boolean false 是否有更新
wgtUrl String '' wgt 包的下载地址,用于 wgt 方式更新。
pkgUrl String '' apk/ipa 包的下载地址或 AppStore 地址,用于整包升级的方式。

代码示例

下面是一个简单的服务端判定的示例,仅做参考,实际开发中根据自身业务需求处理。

var express = require('express');  
var router = express.Router();  
var db = require('./db');  

// TODO 查询配置文件或者数据库信息来确认是否有更新  
function checkUpdate(params, callback) {  
    db.query('一段SQL', function(error, result) {  
        // 这里简单判定下,不相等就是有更新。  
        var currentVersions = params.appVersion.split('.');  
        var resultVersions = result.appVersion.split('.');  

        if (currentVersions[0] < resultVersions[0]) {  
            // 说明有大版本更新  
            callback({  
                update: true,  
                wgtUrl: '',  
                pkgUrl: result.pkgUrl  
            })  
        } else {  
            // 其它情况均认为是小版本更新  
            callback({  
                update: true,  
                wgtUrl: result.wgtUrl,  
                pkgUrl: ''  
            })  
        }  
    });  
}  

router.get('/update/', function(req, res) {  
    var appName = req.query.name;  
    var appVersion = req.query.version;  
    checkUpdate({  
        appName: appName,  
        appVersion: appVersion  
    }, function(error, result) {  
        if (error) {  
            throw error;  
        }  
        res.json(result);  
    });  
});

注意事项

  • 以上约定,仅做参考。
  • 服务端的具体判定逻辑,请根据自身的业务逻辑灵活处理。
  • 应用中的路径尽量不要包含特殊符号

客户端检测升级

在 App.vue 的 onLaunch 中检测升级,代码如下:

// #ifdef APP-PLUS  
plus.runtime.getProperty(plus.runtime.appid, function(widgetInfo) {  
    uni.request({  
        url: 'http://www.example.com/update/',  
        data: {  
            version: widgetInfo.version,  
            name: widgetInfo.name  
        },  
        success: (result) => {  
            var data = result.data;  
            if (data.update && data.wgtUrl) {  
                uni.downloadFile({  
                    url: data.wgtUrl,  
                    success: (downloadResult) => {  
                        if (downloadResult.statusCode === 200) {  
                            plus.runtime.install(downloadResult.tempFilePath, {  
                                force: false  
                            }, function() {  
                                console.log('install success...');  
                                plus.runtime.restart();  
                            }, function(e) {  
                                console.error('install fail...');  
                            });  
                        }  
                    }  
                });  
            }  
        }  
    });  
});  
// #endif

不支持的情况

  • SDK 部分有调整,比如新增了 Maps 模块等,不可通过此方式升级,必须通过整包的方式升级。
  • 原生插件的增改,同样不能使用此方式。
    对于老的非自定义组件编译模式,这种模式已经被淘汰下线。但以防万一也需要说明下,老的非自定义组件编译模式,如果之前工程没有 nvue 文件,但更新中新增了 nvue 文件,不能使用此方式。因为非自定义组件编译模式如果没有nvue文件是不会打包weex引擎进去的,原生引擎无法动态添加。自定义组件模式默认就含着weex引擎,不管工程下有没有nvue文件。

注意事项

  • 条件编译,仅在 App 平台执行此升级逻辑。
  • appid 以及版本信息等,在 HBuilderX 真机运行开发期间,均为 HBuilder 这个应用的信息,因此需要打包自定义基座或正式包测试升级功能。
  • plus.runtime.version 或者 uni.getSystemInfo() 读取到的是 apk/ipa 包的版本号,而非 manifest.json 资源中的版本信息,所以这里用 plus.runtime.getProperty() 来获取相关信息。
  • 安装 wgt 资源包成功后,必须执行 plus.runtime.restart(),否则新的内容并不会生效。
  • 如果App的原生引擎不升级,只升级wgt包时需要注意测试wgt资源和原生基座的兼容性。平台默认会对不匹配的版本进行提醒,如果自测没问题,可以在manifest中配置忽略提示,详见https://ask.dcloud.net.cn/article/35627
  • www.example.com 是一个仅用做示例说明的地址,实际应用中应该是真实的 IP 或有效域名,请勿直接复制粘贴使用。

关于热更新是否影响应用上架

应用市场为了防止开发者不经市场审核许可,给用户提供违法内容,对热更新大多持排斥态度。

但实际上热更新使用非常普遍,不管是原生开发中还是跨平台开发。

Apple曾经禁止过jspatch,但没有打击其他的热更新方案,包括cordovar、react native、DCloud。封杀jspatch其实是因为jspatch有严重安全漏洞,可以被黑客利用,造成三方黑客可篡改其他App的数据。

使用热更新需要注意:

  • 上架审核期间不要弹出热更新提示
  • 热更新内容使用https下载,避免被三方网络劫持
  • 不要更新违法内容、不要通过热更新破坏应用市场的利益,比如iOS的虚拟支付要老老实实给Apple分钱

如果你的应用没有犯这些错误,应用市场是不会管的。

继续阅读 »

官方已发布APP升级中心,支持原生APP整包升级和wgt资源包升级。详见https://uniapp.dcloud.io/uniCloud/upgrade-center

======如下是官方APP升级中心发布之前的文章,供老用户参考============

注:本文为前端代码资源热更新。如果是整包升级,另见文档https://ask.dcloud.net.cn/article/34972

HBuilderX 1.6.5 起,uni-app 支持生成 App 资源升级包。

生成 App 资源升级包

修改版本号

首先,更新 manifest.json 中的版本号。
比如之前是 1.0.0,那么新版本应该是 1.0.1 或 1.1.0 这样。

发行

然后,在 HBuilderX 中生成升级包(wgt)。
菜单->发行->原生App-制作移动App资源升级包

生成结束会在控制台告知升级包的输出位置。

安装资源升级包

应用的升级需要服务端与客户端配合完成,下面以本地测试过程中的操作举例说明:

存放资源

将 %appid%.wgt 文件存放在服务器的 static 目录下,即 http://www.example.com/static/UNI832D722.wgt。

服务端接口

约定检测升级的接口,地址为:http://www.example.com/update/

传入参数

参数名 类型 默认值 说明
name String '' 客户端读取到的应用名称,定义这个参数可以方便多个应用复用接口。
version String '' 客户端读取到的版本号信息

返回参数

参数名 类型 默认值 说明
update Boolean false 是否有更新
wgtUrl String '' wgt 包的下载地址,用于 wgt 方式更新。
pkgUrl String '' apk/ipa 包的下载地址或 AppStore 地址,用于整包升级的方式。

代码示例

下面是一个简单的服务端判定的示例,仅做参考,实际开发中根据自身业务需求处理。

var express = require('express');  
var router = express.Router();  
var db = require('./db');  

// TODO 查询配置文件或者数据库信息来确认是否有更新  
function checkUpdate(params, callback) {  
    db.query('一段SQL', function(error, result) {  
        // 这里简单判定下,不相等就是有更新。  
        var currentVersions = params.appVersion.split('.');  
        var resultVersions = result.appVersion.split('.');  

        if (currentVersions[0] < resultVersions[0]) {  
            // 说明有大版本更新  
            callback({  
                update: true,  
                wgtUrl: '',  
                pkgUrl: result.pkgUrl  
            })  
        } else {  
            // 其它情况均认为是小版本更新  
            callback({  
                update: true,  
                wgtUrl: result.wgtUrl,  
                pkgUrl: ''  
            })  
        }  
    });  
}  

router.get('/update/', function(req, res) {  
    var appName = req.query.name;  
    var appVersion = req.query.version;  
    checkUpdate({  
        appName: appName,  
        appVersion: appVersion  
    }, function(error, result) {  
        if (error) {  
            throw error;  
        }  
        res.json(result);  
    });  
});

注意事项

  • 以上约定,仅做参考。
  • 服务端的具体判定逻辑,请根据自身的业务逻辑灵活处理。
  • 应用中的路径尽量不要包含特殊符号

客户端检测升级

在 App.vue 的 onLaunch 中检测升级,代码如下:

// #ifdef APP-PLUS  
plus.runtime.getProperty(plus.runtime.appid, function(widgetInfo) {  
    uni.request({  
        url: 'http://www.example.com/update/',  
        data: {  
            version: widgetInfo.version,  
            name: widgetInfo.name  
        },  
        success: (result) => {  
            var data = result.data;  
            if (data.update && data.wgtUrl) {  
                uni.downloadFile({  
                    url: data.wgtUrl,  
                    success: (downloadResult) => {  
                        if (downloadResult.statusCode === 200) {  
                            plus.runtime.install(downloadResult.tempFilePath, {  
                                force: false  
                            }, function() {  
                                console.log('install success...');  
                                plus.runtime.restart();  
                            }, function(e) {  
                                console.error('install fail...');  
                            });  
                        }  
                    }  
                });  
            }  
        }  
    });  
});  
// #endif

不支持的情况

  • SDK 部分有调整,比如新增了 Maps 模块等,不可通过此方式升级,必须通过整包的方式升级。
  • 原生插件的增改,同样不能使用此方式。
    对于老的非自定义组件编译模式,这种模式已经被淘汰下线。但以防万一也需要说明下,老的非自定义组件编译模式,如果之前工程没有 nvue 文件,但更新中新增了 nvue 文件,不能使用此方式。因为非自定义组件编译模式如果没有nvue文件是不会打包weex引擎进去的,原生引擎无法动态添加。自定义组件模式默认就含着weex引擎,不管工程下有没有nvue文件。

注意事项

  • 条件编译,仅在 App 平台执行此升级逻辑。
  • appid 以及版本信息等,在 HBuilderX 真机运行开发期间,均为 HBuilder 这个应用的信息,因此需要打包自定义基座或正式包测试升级功能。
  • plus.runtime.version 或者 uni.getSystemInfo() 读取到的是 apk/ipa 包的版本号,而非 manifest.json 资源中的版本信息,所以这里用 plus.runtime.getProperty() 来获取相关信息。
  • 安装 wgt 资源包成功后,必须执行 plus.runtime.restart(),否则新的内容并不会生效。
  • 如果App的原生引擎不升级,只升级wgt包时需要注意测试wgt资源和原生基座的兼容性。平台默认会对不匹配的版本进行提醒,如果自测没问题,可以在manifest中配置忽略提示,详见https://ask.dcloud.net.cn/article/35627
  • www.example.com 是一个仅用做示例说明的地址,实际应用中应该是真实的 IP 或有效域名,请勿直接复制粘贴使用。

关于热更新是否影响应用上架

应用市场为了防止开发者不经市场审核许可,给用户提供违法内容,对热更新大多持排斥态度。

但实际上热更新使用非常普遍,不管是原生开发中还是跨平台开发。

Apple曾经禁止过jspatch,但没有打击其他的热更新方案,包括cordovar、react native、DCloud。封杀jspatch其实是因为jspatch有严重安全漏洞,可以被黑客利用,造成三方黑客可篡改其他App的数据。

使用热更新需要注意:

  • 上架审核期间不要弹出热更新提示
  • 热更新内容使用https下载,避免被三方网络劫持
  • 不要更新违法内容、不要通过热更新破坏应用市场的利益,比如iOS的虚拟支付要老老实实给Apple分钱

如果你的应用没有犯这些错误,应用市场是不会管的。

收起阅读 »

寻求接入过百川的相关原生开发者,安卓和ios

外包

随着业务的推进,需要找开发过淘宝百川会js的原生开发者(需要原生层和js相互调用),实现百川淘宝购物车的功能,百川已经接入,有些不完善,在此基础上进行完善,需要开发2端,苹果和安卓,有能接的联系qq:2764388888 VX:254228737, 详谈

随着业务的推进,需要找开发过淘宝百川会js的原生开发者(需要原生层和js相互调用),实现百川淘宝购物车的功能,百川已经接入,有些不完善,在此基础上进行完善,需要开发2端,苹果和安卓,有能接的联系qq:2764388888 VX:254228737, 详谈

谈谈uni.chooseImage的sizeType问题

我测试了uni.chooseImage的sizeType,
1、压缩出来的图片太狠了,原来分辨率很高的图片,压缩后只有640×960,能否增加个自定义压缩参数呢?比如:长边值和ql质量

2、https://uniapp.dcloud.io/api/media/image?id=chooseimage 这一页文档介绍的是original 原图和compressed 压缩图 ,但demo中用的是['压缩', '原图', '压缩或原图'],以及sourceType文档介绍的是album 从相册选图,camera 使用相机,文档用的是['拍照', '相册', '拍照或相册'] ,为啥也生效了呢?

继续阅读 »

我测试了uni.chooseImage的sizeType,
1、压缩出来的图片太狠了,原来分辨率很高的图片,压缩后只有640×960,能否增加个自定义压缩参数呢?比如:长边值和ql质量

2、https://uniapp.dcloud.io/api/media/image?id=chooseimage 这一页文档介绍的是original 原图和compressed 压缩图 ,但demo中用的是['压缩', '原图', '压缩或原图'],以及sourceType文档介绍的是album 从相册选图,camera 使用相机,文档用的是['拍照', '相册', '拍照或相册'] ,为啥也生效了呢?

收起阅读 »

uni-app 中保持用户登录状态

登录状态 uniapp

在应用中保持登录状态是一个应用常见的需求,本文简单介绍下在 uni-app 中如何保存用户登录状态。

简介

uni-app 中不支持读写 cookie,所以不能如传统的应用那样通过读取 cookie 来判断是否是登录状态。

在 uni-app 进行登录操作时,可以将需要校验的数据放在 uni.request 的 data 中,也可以在 header 里设置 token,使用 token 进行登录状态校验。

流程:首页为未登录状态 => 进行登录 => 首页状态改变 => 退出应用再次进入仍然是已登录状态。

vuex

使用 vuex 进行管理登陆状态和保存用户信息,下面是部分代码。

const store = new Vuex.Store({  
    state: {  
        uerInfo: {},  
        hasLogin: false  
    },  
    mutations: {  
        login(state, provider) {//改变登录状态  
            state.hasLogin = true  
            state.uerInfo.token = provider.token  
            state.uerInfo.userName = provider.user_name  
            uni.setStorage({//将用户信息保存在本地  
                key: 'uerInfo',  
                data: provider  
            })  
        },  
        logout(state) {//退出登录  
            state.hasLogin = false  
            state.uerInfo = {}  
            uni.removeStorage({  
                key: 'uerInfo'  
            })  
        }  
    }  
})

登录

在 login.vue(登录页面)输入用户名密码后,调用 uni.request 进行登录,登录成功后调用 vuex 的方法改变应用的登陆状态。

<script>  
    import {  
        mapMutations  
    } from 'vuex';  
    export default {  
        methods: {  
            bindLogin(e) {  
                let name = e.detail.value.nameValue,  
                    password = e.detail.value.passwordValue;  
                uni.request({  
                    url: `${this.$serverUrl}/login.php`,  
                    header: {  
                        "Content-Type": "application/x-www-form-urlencoded"  
                    },  
                    data: {  
                        "username": name,  
                        "password": password  
                    },  
                    method: "POST",  
                    success: (e) => {  
                        if (e.data.code === 0) {//登录成功后改变vuex的状态,并退出登录页面  
                            this.login(e.data)  
                            uni.navigateBack()  
                        }  
                    }  
                })  
            },  
            ...mapMutations(['login'])  
        }  
    }  
</script>

改变首页状态

通过 vuex 中保存的 hasLogin 判断是否是登录状态,从而显示不同的内容。

<template>  
    <view class="page">  
        <view v-if="!hasLogin">现在是未登录状态,点击按钮进行登录</view>  
        <view v-else>现在是登录状态,您的用户id是:{{uerInfo.userName}}</view>  
        <button type="primary" @click="bindLogin">{{hasLogin ? '退出登录' : '登录'}}</button>  
    </view>  
</template>  
<script>  
    import {  
        mapState,  
        mapMutations  
    } from 'vuex';  
    export default {  
        computed: mapState(['hasLogin','uerInfo']),  
        methods: {  
            ...mapMutations(['logout']),  
            bindLogin() {  
                if (this.hasLogin) {  
                    this.logout()  
                } else {  
                    uni.navigateTo({  
                        url: '/pages/login/login'  
                    })  
                }  
            }  
        }  
    }  
</script>

再次进入应用

在 App.vue 中判断用户是否保存用户信息 "uerInfo",如果保存则认为是登录状态,未保存则为未登录状态。

App.vue 中得到用户信息后需要同步改变 vuex 的状态,使所有页面都能共享登陆状态与用户信息。

<script>  
    import {  
        mapMutations  
    } from 'vuex';  
    export default {  
        onLaunch: function () {  
            uni.getStorage({//获得保存在本地的用户信息  
                key: 'uerInfo',  
                success:(res) => {  
                    this.login(res.data);  
                    uni.request({// 再次校验并刷新token的有效时间  
                        url: `${this.$serverUrl}/auth.php`,  
                        header: {  
                            "Content-Type": "application/x-www-form-urlencoded",  
                            "Token":res.data.token  
                        },  
                        data: {  
                            "username":res.data.user_name  
                        },  
                        method: "POST",  
                        success: (e) => {  
                            if (e.statusCode === 200 && e.data.code === 0) {  
                                this.login(e.data);  
                            }  
                        }  
                    })  
                }  
            });  
        },  
        methods: {  
            ...mapMutations(['login'])  
        }  
    }  
</script>

附件为demo,可直接在 HBuilderX 中运行体验整个登录流程。

继续阅读 »

在应用中保持登录状态是一个应用常见的需求,本文简单介绍下在 uni-app 中如何保存用户登录状态。

简介

uni-app 中不支持读写 cookie,所以不能如传统的应用那样通过读取 cookie 来判断是否是登录状态。

在 uni-app 进行登录操作时,可以将需要校验的数据放在 uni.request 的 data 中,也可以在 header 里设置 token,使用 token 进行登录状态校验。

流程:首页为未登录状态 => 进行登录 => 首页状态改变 => 退出应用再次进入仍然是已登录状态。

vuex

使用 vuex 进行管理登陆状态和保存用户信息,下面是部分代码。

const store = new Vuex.Store({  
    state: {  
        uerInfo: {},  
        hasLogin: false  
    },  
    mutations: {  
        login(state, provider) {//改变登录状态  
            state.hasLogin = true  
            state.uerInfo.token = provider.token  
            state.uerInfo.userName = provider.user_name  
            uni.setStorage({//将用户信息保存在本地  
                key: 'uerInfo',  
                data: provider  
            })  
        },  
        logout(state) {//退出登录  
            state.hasLogin = false  
            state.uerInfo = {}  
            uni.removeStorage({  
                key: 'uerInfo'  
            })  
        }  
    }  
})

登录

在 login.vue(登录页面)输入用户名密码后,调用 uni.request 进行登录,登录成功后调用 vuex 的方法改变应用的登陆状态。

<script>  
    import {  
        mapMutations  
    } from 'vuex';  
    export default {  
        methods: {  
            bindLogin(e) {  
                let name = e.detail.value.nameValue,  
                    password = e.detail.value.passwordValue;  
                uni.request({  
                    url: `${this.$serverUrl}/login.php`,  
                    header: {  
                        "Content-Type": "application/x-www-form-urlencoded"  
                    },  
                    data: {  
                        "username": name,  
                        "password": password  
                    },  
                    method: "POST",  
                    success: (e) => {  
                        if (e.data.code === 0) {//登录成功后改变vuex的状态,并退出登录页面  
                            this.login(e.data)  
                            uni.navigateBack()  
                        }  
                    }  
                })  
            },  
            ...mapMutations(['login'])  
        }  
    }  
</script>

改变首页状态

通过 vuex 中保存的 hasLogin 判断是否是登录状态,从而显示不同的内容。

<template>  
    <view class="page">  
        <view v-if="!hasLogin">现在是未登录状态,点击按钮进行登录</view>  
        <view v-else>现在是登录状态,您的用户id是:{{uerInfo.userName}}</view>  
        <button type="primary" @click="bindLogin">{{hasLogin ? '退出登录' : '登录'}}</button>  
    </view>  
</template>  
<script>  
    import {  
        mapState,  
        mapMutations  
    } from 'vuex';  
    export default {  
        computed: mapState(['hasLogin','uerInfo']),  
        methods: {  
            ...mapMutations(['logout']),  
            bindLogin() {  
                if (this.hasLogin) {  
                    this.logout()  
                } else {  
                    uni.navigateTo({  
                        url: '/pages/login/login'  
                    })  
                }  
            }  
        }  
    }  
</script>

再次进入应用

在 App.vue 中判断用户是否保存用户信息 "uerInfo",如果保存则认为是登录状态,未保存则为未登录状态。

App.vue 中得到用户信息后需要同步改变 vuex 的状态,使所有页面都能共享登陆状态与用户信息。

<script>  
    import {  
        mapMutations  
    } from 'vuex';  
    export default {  
        onLaunch: function () {  
            uni.getStorage({//获得保存在本地的用户信息  
                key: 'uerInfo',  
                success:(res) => {  
                    this.login(res.data);  
                    uni.request({// 再次校验并刷新token的有效时间  
                        url: `${this.$serverUrl}/auth.php`,  
                        header: {  
                            "Content-Type": "application/x-www-form-urlencoded",  
                            "Token":res.data.token  
                        },  
                        data: {  
                            "username":res.data.user_name  
                        },  
                        method: "POST",  
                        success: (e) => {  
                            if (e.statusCode === 200 && e.data.code === 0) {  
                                this.login(e.data);  
                            }  
                        }  
                    })  
                }  
            });  
        },  
        methods: {  
            ...mapMutations(['login'])  
        }  
    }  
</script>

附件为demo,可直接在 HBuilderX 中运行体验整个登录流程。

收起阅读 »