HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

相册多选图片,压缩图片异步问题解决方案(Vue 和 html5+结合使用, 离线打包APP)

我的是Vue项目
/**

  • 从相册选择
    */
    pictrueImg () {
    let maxImgCount = 9 - this.imgList.length
    mui("#picture").popover("hide")
    plus.gallery.pick((e) => {
    this.imgFileArray = e.files
    this.compressImg(0)
    }, (e) => {
    mui.toast('取消选择图片')
    }, {filter:"image",multiple:true,maximum:maxImgCount,system:false,onmaxed:() => {
    plus.nativeUI.alert('最多只能选择' + maxImgCount + '张图片');
    }
    })
    },
    /**
    • 递归函数压缩图片
      */
      compressImg (num) {
      var imgFile = this.imgFileArray[num]
      var name = imgFile.substr(imgFile.lastIndexOf('/') + 1)
      plus.zip.compressImage({
      src: imgFile,
      dst: '_doc/' + name,
      overwrite: true,
      quality: 50
      }, (zip) => {
      this.imgList.push({
      imgUrl: zip.target,
      imgNumber: this.imgNumber ++
      })
      this.compressImg(num + 1)
      }, (zipe) => {
      mui.toast('压缩失败!')
      })
      },
继续阅读 »

我的是Vue项目
/**

  • 从相册选择
    */
    pictrueImg () {
    let maxImgCount = 9 - this.imgList.length
    mui("#picture").popover("hide")
    plus.gallery.pick((e) => {
    this.imgFileArray = e.files
    this.compressImg(0)
    }, (e) => {
    mui.toast('取消选择图片')
    }, {filter:"image",multiple:true,maximum:maxImgCount,system:false,onmaxed:() => {
    plus.nativeUI.alert('最多只能选择' + maxImgCount + '张图片');
    }
    })
    },
    /**
    • 递归函数压缩图片
      */
      compressImg (num) {
      var imgFile = this.imgFileArray[num]
      var name = imgFile.substr(imgFile.lastIndexOf('/') + 1)
      plus.zip.compressImage({
      src: imgFile,
      dst: '_doc/' + name,
      overwrite: true,
      quality: 50
      }, (zip) => {
      this.imgList.push({
      imgUrl: zip.target,
      imgNumber: this.imgNumber ++
      })
      this.compressImg(num + 1)
      }, (zipe) => {
      mui.toast('压缩失败!')
      })
      },
收起阅读 »

二维码:解决安卓从相册选中图片无法识别

plus.gallery.pick(function(path) {
if(mui.os.ios) {
plus.barcode.scan(path, onmarked, function(error) {
mui.alert("无法识别此图片");
});
} else {
var img = new Image();
img.src = path;
img.onload = function() { //要先确保图片完整获取到,这是个异步事件
var bitmap = new plus.nativeObj.Bitmap();
var canvas = document.createElement("canvas");
canvas.width = img.width / 20;
canvas.height = img.height / 20;
canvas.getContext("2d").drawImage(img, 0, 0, canvas.width, canvas.height);
var dataURL = canvas.toDataURL();
var tempImg = "_doc/img" + new Date().getTime() + ".png";
bitmap.loadBase64Data(dataURL, function() {
console.log("创建成功");
bitmap.save(tempImg, {
overwrite: true,
quality: 100,
format: "png"
}, function() {
console.log("保存成功");
bitmap && bitmap.recycle();
bitmap && bitmap.clear();
plus.barcode.scan(tempImg, function(type, result) {
//这是扫描出来的结果,带引号
result = result.replace(/"/g, '');
}, function(error) {
console.log("无法识别此图片");
});
}, function() {
console.log("保存失败");
});
}, function() {
console.log("创建失败");
});
};
}
});

继续阅读 »

plus.gallery.pick(function(path) {
if(mui.os.ios) {
plus.barcode.scan(path, onmarked, function(error) {
mui.alert("无法识别此图片");
});
} else {
var img = new Image();
img.src = path;
img.onload = function() { //要先确保图片完整获取到,这是个异步事件
var bitmap = new plus.nativeObj.Bitmap();
var canvas = document.createElement("canvas");
canvas.width = img.width / 20;
canvas.height = img.height / 20;
canvas.getContext("2d").drawImage(img, 0, 0, canvas.width, canvas.height);
var dataURL = canvas.toDataURL();
var tempImg = "_doc/img" + new Date().getTime() + ".png";
bitmap.loadBase64Data(dataURL, function() {
console.log("创建成功");
bitmap.save(tempImg, {
overwrite: true,
quality: 100,
format: "png"
}, function() {
console.log("保存成功");
bitmap && bitmap.recycle();
bitmap && bitmap.clear();
plus.barcode.scan(tempImg, function(type, result) {
//这是扫描出来的结果,带引号
result = result.replace(/"/g, '');
}, function(error) {
console.log("无法识别此图片");
});
}, function() {
console.log("保存失败");
});
}, function() {
console.log("创建失败");
});
};
}
});

收起阅读 »

QQ第三方登陆的那些坑

APP开发接近尾声.却在即将发布的时候发现APP 的QQ登陆授权凭证 和WEB版本无法共用...要了亲命了...于是各种搜索..下面吧解决办法分享给大家.

  1. 首先,要用发一个邮件 给腾讯互联平台客服 connect@qq.com,说明要APP共用数据,进行应用 APPID合并 分别提供WEB/手机应用的 APPID/appkey.并提供网站的ICP备案查询截图以及帐号认证的营业执照什么的.并且告知,以某一个APPID的用户数据为原有的主应用.

  2. 如果上述的邮件进行正常.会受到客服回信.已经批准什么的 邮件还会说明启用共用unionid .... 并且可通过接口进行获取:https://graph.qq.com/oauth2.0/me?access_token=ACCESSTOKEN&unionid=1....

不过HB 的第三方登陆,QQ授权并未封装获取unionid 的方法.所以,要自己再次获得授权用户的unionid..好在这部分简单得很


/*  
 * 获取QQ登陆unionID  
 */  
function getQQunionID(ACCESSTOKEN,callback)  
{     
    mui.ajax({  
        url: "https://graph.qq.com/oauth2.0/me?access_token="+ACCESSTOKEN+"&unionid=1",  
        async: true,  
        crossDomain: true, //强制使用5+跨域  
        type: 'get',          
        timeout: 50000,  
        success: function(data) {             
                if(data.indexOf("error")<=-1)  
               {  
                eval(data);  
               }  
               else{  
                mui.toast("QQ unionID凭证获取错误:"+data);  
               }  
        },  
        error: function(xhr, type, errorThrown) {  
            mui.toast("QQ unionID凭证网络访问错误:"+type);  
        }  
    });  
}  

拿去用吧:ACCESSTOKEN 是用户的ACCESSTOKEN,callback 回调方法...
这个接口访问的时候返回的是字符串:callback({appid:XXX,openid:XXX,unionid:XXX}); 所以直接eval......

看到此不要高兴得太早,如果你原来有应用的APP并且有留存用户数据...那么好了 OPENID 还是每个APPID 不同的 ,只有unionid 才会相同....怎么解? 经过各种折腾...才知道 再次回复腾讯邮件 说明需要 申请 存量用户 转为 unionid 的临时接口, 再次提供 临时接口使用的APPID 和APPKEY...然后就等着回复把..

最后怎样?写个程序 按照再次回复中临时接口的使用方法,遍历所有每个用户的原有OPENID ,再查询到新的 unionid,然后更新原有登陆凭证...

最后别忘记 如果原有登陆是WEB端...要更改登陆逻辑.需要再次获取 unionid 并储存.

这样才能保证WEB APP 等等登陆凭证的统一性.....

虽然以上解决看起来很简单.不过在网上确实没有一篇文章进行系统性的说明....都是本人一步步查..问客服才最终走到最后一步,记录下来 希望能够帮助遇到此问题倒霉程序员们吧....

继续阅读 »

APP开发接近尾声.却在即将发布的时候发现APP 的QQ登陆授权凭证 和WEB版本无法共用...要了亲命了...于是各种搜索..下面吧解决办法分享给大家.

  1. 首先,要用发一个邮件 给腾讯互联平台客服 connect@qq.com,说明要APP共用数据,进行应用 APPID合并 分别提供WEB/手机应用的 APPID/appkey.并提供网站的ICP备案查询截图以及帐号认证的营业执照什么的.并且告知,以某一个APPID的用户数据为原有的主应用.

  2. 如果上述的邮件进行正常.会受到客服回信.已经批准什么的 邮件还会说明启用共用unionid .... 并且可通过接口进行获取:https://graph.qq.com/oauth2.0/me?access_token=ACCESSTOKEN&unionid=1....

不过HB 的第三方登陆,QQ授权并未封装获取unionid 的方法.所以,要自己再次获得授权用户的unionid..好在这部分简单得很


/*  
 * 获取QQ登陆unionID  
 */  
function getQQunionID(ACCESSTOKEN,callback)  
{     
    mui.ajax({  
        url: "https://graph.qq.com/oauth2.0/me?access_token="+ACCESSTOKEN+"&unionid=1",  
        async: true,  
        crossDomain: true, //强制使用5+跨域  
        type: 'get',          
        timeout: 50000,  
        success: function(data) {             
                if(data.indexOf("error")<=-1)  
               {  
                eval(data);  
               }  
               else{  
                mui.toast("QQ unionID凭证获取错误:"+data);  
               }  
        },  
        error: function(xhr, type, errorThrown) {  
            mui.toast("QQ unionID凭证网络访问错误:"+type);  
        }  
    });  
}  

拿去用吧:ACCESSTOKEN 是用户的ACCESSTOKEN,callback 回调方法...
这个接口访问的时候返回的是字符串:callback({appid:XXX,openid:XXX,unionid:XXX}); 所以直接eval......

看到此不要高兴得太早,如果你原来有应用的APP并且有留存用户数据...那么好了 OPENID 还是每个APPID 不同的 ,只有unionid 才会相同....怎么解? 经过各种折腾...才知道 再次回复腾讯邮件 说明需要 申请 存量用户 转为 unionid 的临时接口, 再次提供 临时接口使用的APPID 和APPKEY...然后就等着回复把..

最后怎样?写个程序 按照再次回复中临时接口的使用方法,遍历所有每个用户的原有OPENID ,再查询到新的 unionid,然后更新原有登陆凭证...

最后别忘记 如果原有登陆是WEB端...要更改登陆逻辑.需要再次获取 unionid 并储存.

这样才能保证WEB APP 等等登陆凭证的统一性.....

虽然以上解决看起来很简单.不过在网上确实没有一篇文章进行系统性的说明....都是本人一步步查..问客服才最终走到最后一步,记录下来 希望能够帮助遇到此问题倒霉程序员们吧....

收起阅读 »

有个小项目寻H5+开发人员,包含前后端

外包

有个小项目寻H5+开发人员,包含前后端,后端THINKPHP+MYSQL,请联系QQ994089287

有个小项目寻H5+开发人员,包含前后端,后端THINKPHP+MYSQL,请联系QQ994089287

Hbuilder支持php版本过低对短数组语法识别错误造成的大纲无法显示问题解决方案

PHP

这个问题困扰了我足有两年之久,无论是百度,还是在这里的问答,发了太多的请求贴,截止到现在也没有得到有效的解决办法
今天找了一天的IDE,都打算弃用了Hbuilder了~

先说问题吧,内置的aptana这个插件大概是不能更新了,我之前没用过eclipse,具体怎么玩也不清楚,但是这个插件按照官网的方法更新或者安装是行不通的。起初以为是本地环境的php版本问题,结果试了好久发现没卵用,后来才发现可能是这个aptana的问题。

但是很无奈,这个aptana我试了太多办法也无法更新。
今天偶然间看到一个配置项,语法验证器!对,你没看错,问题就出在了这里,事实上我在之前也发过帖子来说明的,当语法出现了aptana不能正确解析的时候,语法验证会提示语法错误,此时大纲列表也就不显示了

目前出现这种问题有两种,第一个是session,不能使用session()[]这种形式的语法,会报错,但是其它IDE就不会
第二种则是最常见的一种,php的短数组,只有团队内有一人动过这个文件,以这种形式写的数组,该文件都不再能显示大纲

**解决办法:

  1. 右键项目属性 - PHP开发 - PHP版本(默认5.3),调整为5.4.x
  2. 工具 - 选项 - HBuilder - 语法验证器设置 - PHP 语法验证器 -> 点加号,增加正则表达式用以过滤错误或警告**

短数组可以使用这个正则:

\(\[

添加完成后确定,关闭当前php文件,重启IDE,再次打开后发现久违的大纲又出来了!!!!

就是这么简单的一个处理方法,但是,欸,两年了!

~不说了

继续阅读 »

这个问题困扰了我足有两年之久,无论是百度,还是在这里的问答,发了太多的请求贴,截止到现在也没有得到有效的解决办法
今天找了一天的IDE,都打算弃用了Hbuilder了~

先说问题吧,内置的aptana这个插件大概是不能更新了,我之前没用过eclipse,具体怎么玩也不清楚,但是这个插件按照官网的方法更新或者安装是行不通的。起初以为是本地环境的php版本问题,结果试了好久发现没卵用,后来才发现可能是这个aptana的问题。

但是很无奈,这个aptana我试了太多办法也无法更新。
今天偶然间看到一个配置项,语法验证器!对,你没看错,问题就出在了这里,事实上我在之前也发过帖子来说明的,当语法出现了aptana不能正确解析的时候,语法验证会提示语法错误,此时大纲列表也就不显示了

目前出现这种问题有两种,第一个是session,不能使用session()[]这种形式的语法,会报错,但是其它IDE就不会
第二种则是最常见的一种,php的短数组,只有团队内有一人动过这个文件,以这种形式写的数组,该文件都不再能显示大纲

**解决办法:

  1. 右键项目属性 - PHP开发 - PHP版本(默认5.3),调整为5.4.x
  2. 工具 - 选项 - HBuilder - 语法验证器设置 - PHP 语法验证器 -> 点加号,增加正则表达式用以过滤错误或警告**

短数组可以使用这个正则:

\(\[

添加完成后确定,关闭当前php文件,重启IDE,再次打开后发现久违的大纲又出来了!!!!

就是这么简单的一个处理方法,但是,欸,两年了!

~不说了

收起阅读 »

接外包。小程序、微信、app、vue、mui都可以

外包 移动APP

从事html5开发两年多,期间用mui和hbuilder开发过几个APP,非常熟悉mui和hbuilder。

可以加QQ:2457621435

从事html5开发两年多,期间用mui和hbuilder开发过几个APP,非常熟悉mui和hbuilder。

可以加QQ:2457621435

空闲时间,承接外包

移动APP 外包

本人三年开发经验,接触Hbuiilder和MUI已经两年,用他们做过几个APP。现在有空闲时间,想接APP的外包做,
如果有需要,
请加
QQ:3319718628

本人三年开发经验,接触Hbuiilder和MUI已经两年,用他们做过几个APP。现在有空闲时间,想接APP的外包做,
如果有需要,
请加
QQ:3319718628

mui开发的app里的页面会被手机自带的文件管理工具扫出来

加密

今天本打算打开手机的文件管理工具去找个文件,无意间就发现我做的app里html页面就全部都爆出来了,打开页面里面的东西全部都可以浏览到,假设我在手机上装一个手机版的html编辑器,将这几个页面里的东西稍加修改一下然后保存,路径也没有改变时我重新打开app是不是就是我修改的模样 。这个安全问题假设被别人利用起来危险性无法估计 轻轻松松修改app里面的按钮名称 图片,布局啊随随便便就破解了,甚至绕过你的付费功能 泄露你的后台接口。

希望官方能出点解决方案

继续阅读 »

今天本打算打开手机的文件管理工具去找个文件,无意间就发现我做的app里html页面就全部都爆出来了,打开页面里面的东西全部都可以浏览到,假设我在手机上装一个手机版的html编辑器,将这几个页面里的东西稍加修改一下然后保存,路径也没有改变时我重新打开app是不是就是我修改的模样 。这个安全问题假设被别人利用起来危险性无法估计 轻轻松松修改app里面的按钮名称 图片,布局啊随随便便就破解了,甚至绕过你的付费功能 泄露你的后台接口。

希望官方能出点解决方案

收起阅读 »

分享离线打包js的加密方法

加密 技术分享 App离线打包

最近在做一个app小工具,打算发布在ios和android平台,又不想双平台各写一份代码,就这样mui成为了选项。

顺利做完要发布前,代码的安全性成了考虑。先说下个人的经历,开发技术栈主要集中在iOS app和手游上,前端算是菜鸟,只是稍有入门,js风格没有讲究范式,因此代码写的很随兴,全局变量、全局函数四处飞,写的时候是爽了,要做压缩混淆时就有点傻眼了。看了各种js的压缩教程,也试了各种压缩和混淆工具后,效果都不是太好,全局变量和函数名基本都是明的,也有考试过eval这种混淆方式,虽然混淆后是面目全非了,但是js文件里那个刺眼的eval简直就是在赤裸裸地告诉破解者对应的解密方式。

考虑一番后,打算不走寻常路,对js进行加密(真正意义上的加密,非js混淆),为此我们需要在js载入流程上做改动。

废话不多说,干货开始。

加密后的载入方式如下:

  1. 在plusReady事件触发时先载入解密js的插件,此插件流程在稍后叙述。
  2. 利用此插件载入加密过的js。
  3. 继续执行正常的js逻辑代码。

打包前对敏感的js做加密,再放到包里。

第一点:
需要我们写一个解密的第三方插件,iOS和android各一份。第三方插件的教程在论坛里很清楚,这里各位同学可以自由挑选要使用的加密算法,在native层实现。

第二点:
假定这个包装好的插件入口在plus.jsUtils。
jsUtils.js代码如下:

document.addEventListener( "plusready",  function()  
{  
    var pluginName = 'jsUtils', B = window.plus.bridge;  
    var isBuilder = plus.runtime.version > '8'; //为了确保调试基座也能正常,简单用版本号判断是否调试基座,稳妥做法是用包名判断  
    var bfUtils;  
    if (!isBuilder)  
        jsUtils = {  
                load : function (files, success, fail) {  
                    var callbackId = B.callbackId(success, fail);  
                                return B.exec(pluginName, "load", [callbackId, files]);  
                }  
            };  
        else  
            jsUtils = {  
                load: function (files, success, fail) {  
                    success();  
                    return true;  
                }  
            };  
    window.plus.jsUtils = jsUtils;  
}, false );

html载入页面写法:

<script src="js/jsUtils.js"></script>  
<script>  
mui.init();  
document.addEventListener('plusready', function () {  
    if (plus.jsUtils)  
        plus.jsUtils(['a.js', 'b.js'], init, function() {});  
    else  
        init();  
}, false);  

function init() {  
    //正常的代码逻辑  
}  
</script>

第三方插件执行流程如下:

  1. 读取加密后的js文件内容。
  2. 执行解密操作。
  3. 执行解密后的js代码,回调success函数。在iOS下是[JSFrameContext evaluateJavaScript],android下是IWebview.evalJS (android的evalJS载入是异步,因此要调用带回调参数的的evalJS)。

如此大功告成。

继续阅读 »

最近在做一个app小工具,打算发布在ios和android平台,又不想双平台各写一份代码,就这样mui成为了选项。

顺利做完要发布前,代码的安全性成了考虑。先说下个人的经历,开发技术栈主要集中在iOS app和手游上,前端算是菜鸟,只是稍有入门,js风格没有讲究范式,因此代码写的很随兴,全局变量、全局函数四处飞,写的时候是爽了,要做压缩混淆时就有点傻眼了。看了各种js的压缩教程,也试了各种压缩和混淆工具后,效果都不是太好,全局变量和函数名基本都是明的,也有考试过eval这种混淆方式,虽然混淆后是面目全非了,但是js文件里那个刺眼的eval简直就是在赤裸裸地告诉破解者对应的解密方式。

考虑一番后,打算不走寻常路,对js进行加密(真正意义上的加密,非js混淆),为此我们需要在js载入流程上做改动。

废话不多说,干货开始。

加密后的载入方式如下:

  1. 在plusReady事件触发时先载入解密js的插件,此插件流程在稍后叙述。
  2. 利用此插件载入加密过的js。
  3. 继续执行正常的js逻辑代码。

打包前对敏感的js做加密,再放到包里。

第一点:
需要我们写一个解密的第三方插件,iOS和android各一份。第三方插件的教程在论坛里很清楚,这里各位同学可以自由挑选要使用的加密算法,在native层实现。

第二点:
假定这个包装好的插件入口在plus.jsUtils。
jsUtils.js代码如下:

document.addEventListener( "plusready",  function()  
{  
    var pluginName = 'jsUtils', B = window.plus.bridge;  
    var isBuilder = plus.runtime.version > '8'; //为了确保调试基座也能正常,简单用版本号判断是否调试基座,稳妥做法是用包名判断  
    var bfUtils;  
    if (!isBuilder)  
        jsUtils = {  
                load : function (files, success, fail) {  
                    var callbackId = B.callbackId(success, fail);  
                                return B.exec(pluginName, "load", [callbackId, files]);  
                }  
            };  
        else  
            jsUtils = {  
                load: function (files, success, fail) {  
                    success();  
                    return true;  
                }  
            };  
    window.plus.jsUtils = jsUtils;  
}, false );

html载入页面写法:

<script src="js/jsUtils.js"></script>  
<script>  
mui.init();  
document.addEventListener('plusready', function () {  
    if (plus.jsUtils)  
        plus.jsUtils(['a.js', 'b.js'], init, function() {});  
    else  
        init();  
}, false);  

function init() {  
    //正常的代码逻辑  
}  
</script>

第三方插件执行流程如下:

  1. 读取加密后的js文件内容。
  2. 执行解密操作。
  3. 执行解密后的js代码,回调success函数。在iOS下是[JSFrameContext evaluateJavaScript],android下是IWebview.evalJS (android的evalJS载入是异步,因此要调用带回调参数的的evalJS)。

如此大功告成。

收起阅读 »

ajax在安卓4.1.1里没用!

ajax

用的是官方hello mui
安卓在联想的s890里 系统版本4.1.1
ajax 不管get和post都无效 显示正在请求!

用的是官方hello mui
安卓在联想的s890里 系统版本4.1.1
ajax 不管get和post都无效 显示正在请求!