mui.openWindow新页面无法获取焦点
页面A
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<link href="../css/mui.min.css" rel="stylesheet" />
<style>
</style>
<script src="../js/mui.min.js"></script>
<script type="text/javascript">
mui.init();
mui.plusReady(function() {
document.getElementById("btn").addEventListener("tap", function(e) {
mui.openWindow({
url: 'test2.html',
id: 'test1'
});
}, false);
});
</script>
</head>
<body>test1
<button id="btn">OPEN</button>
</body>
</html>
页面B
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<link href="../css/mui.min.css" rel="stylesheet" />
<style>
</style>
<script src="../js/mui.min.js"></script>
<script type="text/javascript">
mui.init();
mui.plusReady(function() {
document.getElementById("txt").focus();
});
</script>
</head>
<body>test2
<input type="text" id="txt" />
</body>
</html>
页面A点击打开页面B,B页面无法获取焦点,如果直接打开页面B可以获取焦点
页面A
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<link href="../css/mui.min.css" rel="stylesheet" />
<style>
</style>
<script src="../js/mui.min.js"></script>
<script type="text/javascript">
mui.init();
mui.plusReady(function() {
document.getElementById("btn").addEventListener("tap", function(e) {
mui.openWindow({
url: 'test2.html',
id: 'test1'
});
}, false);
});
</script>
</head>
<body>test1
<button id="btn">OPEN</button>
</body>
</html>
页面B
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<link href="../css/mui.min.css" rel="stylesheet" />
<style>
</style>
<script src="../js/mui.min.js"></script>
<script type="text/javascript">
mui.init();
mui.plusReady(function() {
document.getElementById("txt").focus();
});
</script>
</head>
<body>test2
<input type="text" id="txt" />
</body>
</html>
页面A点击打开页面B,B页面无法获取焦点,如果直接打开页面B可以获取焦点
收起阅读 »关于HBuilder的问题提起
第一次注册的时候可能因为服务器的原因发送邮件比较缓慢所以需要等比较久的时间,我等了10多分钟,
第一次注册的时候可能因为服务器的原因发送邮件比较缓慢所以需要等比较久的时间,我等了10多分钟,
mui + react的组件化开发
原文地址:http://www.jianshu.com/p/5698c0edb307
原文地址:http://www.jianshu.com/p/5698c0edb307
wap2app 打包教程
需求明确
此教程适用于利用 HBuilder 云打包 - 打原生安装包(apk/ipa)的用户。
详细步骤
Android
- 需要证书,HBuilder云端打包默认证书是DCloud的公用证书,可以直接用这个证书,也可以使用自有证书,两者不影响安装包的发布,唯一的差别就是证书中开发者和企业信息不同。关于公用证书的信息,请参考Android打包证书; 关于使用自有证书打包,请参考生成Android签名证书
- 需要注意 manifest.json 中的应用信息是否填写正确。如果填写的有问题,打包按钮是会被禁用的。
- 配置打包信息,App包名是必填项,建议使用反向域名风格的字符串,如“com.domainname.appname”。记住这个包名,如果需要实现第三方业务比如个推,地图定位,分享,支付之类会需要你在开发者平台中填写包名。注意:wap2app中如果首页有适配到css,也就是根目录下appid + 'append.css'文件是有内容的,需要在manifest.json中配置 “解压资源后运行”打包之后才会提前注入该css文件,默认是“不解压直接运行”,如下图所示
- 查看打包状态,菜单栏上发行 -> 查看打包状态,打开“查看App打包状态”对话框,可查看打包历史记录和状态
- 下载安装包,在“查看App打包状态”对话框中 “打开下载目录”可查看并下载安装包
- 安装到手机上,有很多手机和电脑的同步工具比如360手机助手,Android文件传输等等。
iOS
iOS打包分为两种:越狱包 和 使用苹果证书 打包。
越狱包
只能安装在已越狱的设备上,只需填写AppID,即可打包。
使用苹果证书打包
可通过iDP证书打包提交到Appstore发布、或通过iEP证书打包在企业内部发布,请点击查看关于iDP和iEP的区别以及如何安装ipa包到手机上
点击菜单栏 发行 -> 打原生安装包,切换到ios ,使用自有证书打包,你会看到如下信息需要你填写,详细说明如下:
- AppID:iOS应用标识,推荐使用反向域名风格的字符串,如“com.domainname.appname”,必须与profile文件绑定的App ID匹配。
- 私钥证书:iOS Certificates文件(.p12);
- 私钥密码:导入私钥证书的密码;
- Profile文件:iOS Provisioning Profile文件(.mobileprovision),必须与苹果App ID和私钥证书区配;
步骤如下:
- 首先得申请证书,需要 profile(.mobileprovision)文件 和 私钥证书(.p12),详细申请证书教程可参考iOS证书(.p12)和描述文件(.mobileprovision)申请
- 配置打包信息,在上一步操作中你可以申请到开发(Development)证书和发布(Distribution)证书以及配套的描述文件,所以此时你可以打出测试包和正式包。两者的区别就是通过iTools安装到手机时,测试包能安装成功,正式包不行。当然,如果你需要在提交审核前测试正式包的话,也可以上传到appsotre上然后通过 testFlight 测试。
- 查看打包状态。菜单栏上发行 -> 查看打包状态,打开“查看App打包状态”对话框,可查看打包历史记录和状态
- 下载安装包,与 Android 的一样
- 安装到手机上,请点击查看如何安装ipa包到手机上
补充说明
- 真机运行时涉及第三方业务比如地图定位,分享,支付默认是支持的,但是打包成原生安装包时,因为需要绑定包名,所以需开发者到相应的开发者平台申请。
- 常见错误请参考App云端打包失败常见问题汇总。
需求明确
此教程适用于利用 HBuilder 云打包 - 打原生安装包(apk/ipa)的用户。
详细步骤
Android
- 需要证书,HBuilder云端打包默认证书是DCloud的公用证书,可以直接用这个证书,也可以使用自有证书,两者不影响安装包的发布,唯一的差别就是证书中开发者和企业信息不同。关于公用证书的信息,请参考Android打包证书; 关于使用自有证书打包,请参考生成Android签名证书
- 需要注意 manifest.json 中的应用信息是否填写正确。如果填写的有问题,打包按钮是会被禁用的。
- 配置打包信息,App包名是必填项,建议使用反向域名风格的字符串,如“com.domainname.appname”。记住这个包名,如果需要实现第三方业务比如个推,地图定位,分享,支付之类会需要你在开发者平台中填写包名。注意:wap2app中如果首页有适配到css,也就是根目录下appid + 'append.css'文件是有内容的,需要在manifest.json中配置 “解压资源后运行”打包之后才会提前注入该css文件,默认是“不解压直接运行”,如下图所示
- 查看打包状态,菜单栏上发行 -> 查看打包状态,打开“查看App打包状态”对话框,可查看打包历史记录和状态
- 下载安装包,在“查看App打包状态”对话框中 “打开下载目录”可查看并下载安装包
- 安装到手机上,有很多手机和电脑的同步工具比如360手机助手,Android文件传输等等。
iOS
iOS打包分为两种:越狱包 和 使用苹果证书 打包。
越狱包
只能安装在已越狱的设备上,只需填写AppID,即可打包。
使用苹果证书打包
可通过iDP证书打包提交到Appstore发布、或通过iEP证书打包在企业内部发布,请点击查看关于iDP和iEP的区别以及如何安装ipa包到手机上
点击菜单栏 发行 -> 打原生安装包,切换到ios ,使用自有证书打包,你会看到如下信息需要你填写,详细说明如下:
- AppID:iOS应用标识,推荐使用反向域名风格的字符串,如“com.domainname.appname”,必须与profile文件绑定的App ID匹配。
- 私钥证书:iOS Certificates文件(.p12);
- 私钥密码:导入私钥证书的密码;
- Profile文件:iOS Provisioning Profile文件(.mobileprovision),必须与苹果App ID和私钥证书区配;
步骤如下:
- 首先得申请证书,需要 profile(.mobileprovision)文件 和 私钥证书(.p12),详细申请证书教程可参考iOS证书(.p12)和描述文件(.mobileprovision)申请
- 配置打包信息,在上一步操作中你可以申请到开发(Development)证书和发布(Distribution)证书以及配套的描述文件,所以此时你可以打出测试包和正式包。两者的区别就是通过iTools安装到手机时,测试包能安装成功,正式包不行。当然,如果你需要在提交审核前测试正式包的话,也可以上传到appsotre上然后通过 testFlight 测试。
- 查看打包状态。菜单栏上发行 -> 查看打包状态,打开“查看App打包状态”对话框,可查看打包历史记录和状态
- 下载安装包,与 Android 的一样
- 安装到手机上,请点击查看如何安装ipa包到手机上
补充说明
- 真机运行时涉及第三方业务比如地图定位,分享,支付默认是支持的,但是打包成原生安装包时,因为需要绑定包名,所以需开发者到相应的开发者平台申请。
- 常见错误请参考App云端打包失败常见问题汇总。
【重要】iOS平台HBuilder8.8.6真机无法运行的处理方法
非常抱歉,由于我们内部工作失误,没有及时更新iOS平台的调试基座打包证书,导致从2017.11.22下午开始,HBuilder8.8.6的iOS平台无法真机运行。
11月22日晚HBuilder已发布紧急更新本(8.8.7),已解决该问题
大家可以升级到最新版HBuilder。
如果不想升级8.8.7,以下是临时解决方案:
- 从这里下载HBuilder调试基座
- 替换HBuilder真机调试安装包目录下的iPhone_base.ipa文件
路径为“%HBuilder%\plugins\com.pandora.tools.android_1.0.0.201711151411\base\”,其中%HBuilder%为HBuilder安装根目录,“com.pandora.tools.android_1.0.0.201711151411”为调试安装包文件夹,后面数字是版本号,如果不存在此文件夹,找到最新的版本号的文件夹即可。
注意:文件名称必须是“iPhone_base.ipa”。 - 删除手机上的HBuilder应用
- 重新真机运行
给开发者带来不便,深表歉意。
非常抱歉,由于我们内部工作失误,没有及时更新iOS平台的调试基座打包证书,导致从2017.11.22下午开始,HBuilder8.8.6的iOS平台无法真机运行。
11月22日晚HBuilder已发布紧急更新本(8.8.7),已解决该问题
大家可以升级到最新版HBuilder。
如果不想升级8.8.7,以下是临时解决方案:
- 从这里下载HBuilder调试基座
- 替换HBuilder真机调试安装包目录下的iPhone_base.ipa文件
路径为“%HBuilder%\plugins\com.pandora.tools.android_1.0.0.201711151411\base\”,其中%HBuilder%为HBuilder安装根目录,“com.pandora.tools.android_1.0.0.201711151411”为调试安装包文件夹,后面数字是版本号,如果不存在此文件夹,找到最新的版本号的文件夹即可。
注意:文件名称必须是“iPhone_base.ipa”。 - 删除手机上的HBuilder应用
- 重新真机运行
给开发者带来不便,深表歉意。
收起阅读 »推送开发指南
简介
推送服务是一项移动应用消息推送服务解决方案,支持Android和iOS两大平台,开发者可以借助该服务,快速构建稳定高效的消息推送系统,及时有效地将服务端消息推送到客户端上,为实时业务需求和产品运营提供技术支持,从而积极地保持与用户的连接,并提高用户活跃度和留存率。本文档帮助开发者理解推送服务的工作流程,手把手介绍所需的各项集成步骤,同时介绍了消息的不同类型特点,供应用开发者根据实际业务需求进行选择。
推送消息
推送消息总共分为通知消息和透传消息两大类。通知消息一般会在系统消息中心通知显示,满足日常的运营需求,而通知消息按照后续动作分类,又可分为启动应用消息(即普通通知消息),打开网页消息,下载链接消息三种;透传消息则会将消息下发到app,后续动作由app进行定制,从而满足业务相关的特定功能需求,注意透传消息需要满足json格式,并包含key分别为title,content,payload的键值对内容,三者缺一不可,如:
透传消息的格式为{title:"通知标题",content:"通知内容",payload:"通知去干嘛这里可以自定义"}
另外5+API提供了推送消息事件监听机制,app接收到消息的“receive”事件和用户点击消息的“click”事件,如当用户点击消息中心里的消息时会启动应用,并且在监听push事件的页面触发“click”事件。API详细介绍移步这里事件监听,并且两个事件根据推送消息类型和格式,手机操作系统,手机网络连接情况的不同,产生不同的触发情况。现总结如下:
推送配置
开发者向个推开放平台进行应用注册,得到appid,appkey,appsecret的值,然后在HBuilder中的项目进行配置,配置步骤参考如下文档:
HBuilder中推送消息模块配置
服务端也需要下载并集成个推相应服务器端SDK下载地址,同时我们提供用php写的服务端开源项目,仅供参考。
推送消息服务器开源项目Github地址
简介
推送服务是一项移动应用消息推送服务解决方案,支持Android和iOS两大平台,开发者可以借助该服务,快速构建稳定高效的消息推送系统,及时有效地将服务端消息推送到客户端上,为实时业务需求和产品运营提供技术支持,从而积极地保持与用户的连接,并提高用户活跃度和留存率。本文档帮助开发者理解推送服务的工作流程,手把手介绍所需的各项集成步骤,同时介绍了消息的不同类型特点,供应用开发者根据实际业务需求进行选择。
推送消息
推送消息总共分为通知消息和透传消息两大类。通知消息一般会在系统消息中心通知显示,满足日常的运营需求,而通知消息按照后续动作分类,又可分为启动应用消息(即普通通知消息),打开网页消息,下载链接消息三种;透传消息则会将消息下发到app,后续动作由app进行定制,从而满足业务相关的特定功能需求,注意透传消息需要满足json格式,并包含key分别为title,content,payload的键值对内容,三者缺一不可,如:
透传消息的格式为{title:"通知标题",content:"通知内容",payload:"通知去干嘛这里可以自定义"}
另外5+API提供了推送消息事件监听机制,app接收到消息的“receive”事件和用户点击消息的“click”事件,如当用户点击消息中心里的消息时会启动应用,并且在监听push事件的页面触发“click”事件。API详细介绍移步这里事件监听,并且两个事件根据推送消息类型和格式,手机操作系统,手机网络连接情况的不同,产生不同的触发情况。现总结如下:
推送配置
开发者向个推开放平台进行应用注册,得到appid,appkey,appsecret的值,然后在HBuilder中的项目进行配置,配置步骤参考如下文档:
HBuilder中推送消息模块配置
服务端也需要下载并集成个推相应服务器端SDK下载地址,同时我们提供用php写的服务端开源项目,仅供参考。
推送消息服务器开源项目Github地址
Android Studio环境进行离线打包
1) 导入项目官网下载的HBuilder离线打包Android版SDK(5+ SDK下载)中项目\Android-SDK@1.9.9.38184_20171023\HBuilder-Hello
1-1) 出现“manifest merger failed with multiple errors,see logs”错误提示
则删除Hbuilder-Hello这个目录里将AndroidManIfest.xml配置了小米推送和小米登录的信息,这个不删掉一定会导致运行报错
1-2) 在真机运行,运行不了,但也不报错,可以考虑离线打包测试(这个错误在离线打包时才显示)
Error:(2) Error: "app_name" is not translated in "zh" (Chinese) [MissingTranslation]
答: 在build.gradle文件中添加:
android{
...
lintOptions{
checkReleaseBuilds false
abortOnError false
}
}
此时,真机运行成功,替换HBuilder中的前端项目到As环境中
2) 替换\Android-SDK@1.9.9.38184_20171023\HBuilder-gm\app\src\main\assets\apps\HelloH5\www目录下内容为新项目NewProject前端内容
直接运行查看效果
3) 如果再次运行时会报错,此时将HBuilder-Hello下\assets\apps\HelloH5\www中的manifest.json替换成原项目中的manifest.json内容,再次运行查看
4) 修改启动图片和应用图标: \Android-SDK@1.9.9.38184_20171023\HBuilder-gm\app\build\intermediates\res\merged\release\
可通过drawable-XXXhdpi文件名查询对应尺寸(可参考: http://blog.csdn.net/gf771115/article/details/50323635)
5) 修改应用名称: \Android-SDK@1.9.9.38184_20171023\HBuilder-gm\app\src\main\res\values\strings.html
结束。
1) 导入项目官网下载的HBuilder离线打包Android版SDK(5+ SDK下载)中项目\Android-SDK@1.9.9.38184_20171023\HBuilder-Hello
1-1) 出现“manifest merger failed with multiple errors,see logs”错误提示
则删除Hbuilder-Hello这个目录里将AndroidManIfest.xml配置了小米推送和小米登录的信息,这个不删掉一定会导致运行报错
1-2) 在真机运行,运行不了,但也不报错,可以考虑离线打包测试(这个错误在离线打包时才显示)
Error:(2) Error: "app_name" is not translated in "zh" (Chinese) [MissingTranslation]
答: 在build.gradle文件中添加:
android{
...
lintOptions{
checkReleaseBuilds false
abortOnError false
}
}
此时,真机运行成功,替换HBuilder中的前端项目到As环境中
2) 替换\Android-SDK@1.9.9.38184_20171023\HBuilder-gm\app\src\main\assets\apps\HelloH5\www目录下内容为新项目NewProject前端内容
直接运行查看效果
3) 如果再次运行时会报错,此时将HBuilder-Hello下\assets\apps\HelloH5\www中的manifest.json替换成原项目中的manifest.json内容,再次运行查看
4) 修改启动图片和应用图标: \Android-SDK@1.9.9.38184_20171023\HBuilder-gm\app\build\intermediates\res\merged\release\
可通过drawable-XXXhdpi文件名查询对应尺寸(可参考: http://blog.csdn.net/gf771115/article/details/50323635)
5) 修改应用名称: \Android-SDK@1.9.9.38184_20171023\HBuilder-gm\app\src\main\res\values\strings.html
结束。
Android7解决plus.runtime.openFile方法打开文件无响应问题(需本地打包并修改SDK)
需修改的类:pdr.jar\io\dcloud\common\adapter\util\PlatformUtil.class
具体方法请参见:解决 Android N 7.0 上 报错:android.os.FileUriExposedException
另外调试中还发现一个问题:
** PLEASE READ ****
- New versions of the Android SDK no longer support the Crypto provider.
- If your app was relying on setSeed() to derive keys from strings, you
- should switch to using SecretKeySpec to load raw key bytes directly OR
- use a real key derivation function (KDF). See advice here :
-
http://android-developers.blogspot.com/2016/06/security-crypto-provider-deprecated-in.html
此问题的解决请参见:Android:7.0 后加密库 Crypto 被废弃后的爬坑指南
需修改的类:pdr.jar\io\dcloud\common\adapter\util\DCloudTrustManager.class
希望dcloud团队能更新此类问题
需修改的类:pdr.jar\io\dcloud\common\adapter\util\PlatformUtil.class
具体方法请参见:解决 Android N 7.0 上 报错:android.os.FileUriExposedException
另外调试中还发现一个问题:
** PLEASE READ ****
- New versions of the Android SDK no longer support the Crypto provider.
- If your app was relying on setSeed() to derive keys from strings, you
- should switch to using SecretKeySpec to load raw key bytes directly OR
- use a real key derivation function (KDF). See advice here :
-
http://android-developers.blogspot.com/2016/06/security-crypto-provider-deprecated-in.html
此问题的解决请参见:Android:7.0 后加密库 Crypto 被废弃后的爬坑指南
需修改的类:pdr.jar\io\dcloud\common\adapter\util\DCloudTrustManager.class
希望dcloud团队能更新此类问题
收起阅读 »有偿找一个会做前端加PHP写后台外包
来一个会做前端加PHP写后台外包
一个前端加 PHP后台!联系QQ 1120094610
速度要快的,有经验的,
来一个会做前端加PHP写后台外包
一个前端加 PHP后台!联系QQ 1120094610
速度要快的,有经验的,
消息推送 - wap2app教程
wap2app应用目前支持集成个推平台,可以向用户发送推送消息。
wap2app的推送开发,分为三个部分:
- 个推平台申请账号及应用登记,获取应用的appid、appkey、appsecret参数;
- 本地manifest.json中配置推送权限及个推参数
- 本地app.js中编写推送消息监听代码
其中,前两项和5+ App的配置方法相同,参考推送插件开发指南即可,其中有推送原理的详细说明;为了便于理解,这里再次简述一下推送的相关概念。
推送概念简述
推送消息分为普通推送和透传推送,区别在于:
- 普通推送只有消息标题和消息内容;
- 透传消息除了消息标题、消息内容外,还有payload字段,payload是一个json对象,可以包含业务自定义参数,比如新闻ID等。
wap2app应用支持click、receive两种事件监听推送消息,主要区别在于:
- 进入手机消息中心的推送,用户点击后触发click事件
- 透传消息不符合规范或iOS应用正处于前台运行时收到推送,此时消息不会进入手机消息中心,而会直接触发receive事件。
Tips:Android平台的普通消息会进入消息中心,但用户点击后仅激活应用,不会触发click事件。
为了完整实现,需要在代码中同时监听click事件和receive事件。
wap2app中的推送监听
wap2app应用需要在app.js的onLaunch事件中监听推送消息,本示例接收透传消息,透传消息中包含新闻ID,用户点击推送消息后,直接打开新闻详情,实现消息直达的需求;推送内容如下:
{title:"推送标题",content:"推送内容",payload:{id:1001}}
示例代码如下:
/**
* 当wap2app初始化完成时,会触发 onLaunch
* @param {Object} options
*/
onLaunch: function (options) {
//应用初始化
/******推送消息监听代码开始******/
//监听click事件,用户从消息中心点击触发的
plus.push.addEventListener("click", function (msg) {
console.log("You clicked: " + msg.title); //推送消息标题
console.log("You clicked: " + msg.content); //推送消息内容
//根据payload传递过来的数据,打开一个详情
var payload = msg.payload;
if (payload) {
// payload 按照规范是 Object,但实际推送过来有可能是 String,需要多一步处理;
if (typeof payload === 'string') {
payload = JSON.parse(payload);
}
if (typeof payload === 'object') {
//payload是一个json对象,可以传递业务数据,开发者可以根据实际需求自定义参数
//本示例在payload中传入新闻id,wap2app接收到推送后,直接打开新闻详情
var detailId = payload.id;
//wap2app.open(url)可以直接打开对应的webview
//这里是示例,实际项目中开发者需根据M站的url拼接页面地址
wap2app.open('https://m.example.com/detial/' + detailId + '.html');
}
}
}, false);
//监听receive事件
plus.push.addEventListener("receive", function (msg) {
console.log("recieve title: " + msg.title); //推送消息标题
console.log("recieve content: " + msg.content); //推送消息内容
//根据payload传递过来的数据,打开一个详情
var payload;
if (msg.payload) {
//如透传消息不符合格式,则“payload”属性为string类型
//这里的示例以json字符串去解析,实际上也可以做字符串匹配
if (typeof (msg.payload) == "string") {
try {
payload = JSON.parse(msg.payload);
} catch (error) {
console.log(error);
}
} else if (typeof (msg.payload) == "object") {
//iOS应用正处于前台运行时收到推送,也触发receive事件,此时payload为json对象
payload = msg.payload;
}
if (payload) {
//本示例在payload中传入新闻id,wap2app接收到推送后,直接打开新闻详情
var detailId = payload.id;
//wap2app.open(url)可以直接打开对应的webview
//这里是示例,实际项目中开发者需根据M站的url拼接页面地址
wap2app.open('https://m.example.com/detial/' + detailId + '.html');
}
}
}, false);
/******推送消息监听代码结束******/
} wap2app应用目前支持集成个推平台,可以向用户发送推送消息。
wap2app的推送开发,分为三个部分:
- 个推平台申请账号及应用登记,获取应用的appid、appkey、appsecret参数;
- 本地manifest.json中配置推送权限及个推参数
- 本地app.js中编写推送消息监听代码
其中,前两项和5+ App的配置方法相同,参考推送插件开发指南即可,其中有推送原理的详细说明;为了便于理解,这里再次简述一下推送的相关概念。
推送概念简述
推送消息分为普通推送和透传推送,区别在于:
- 普通推送只有消息标题和消息内容;
- 透传消息除了消息标题、消息内容外,还有payload字段,payload是一个json对象,可以包含业务自定义参数,比如新闻ID等。
wap2app应用支持click、receive两种事件监听推送消息,主要区别在于:
- 进入手机消息中心的推送,用户点击后触发click事件
- 透传消息不符合规范或iOS应用正处于前台运行时收到推送,此时消息不会进入手机消息中心,而会直接触发receive事件。
Tips:Android平台的普通消息会进入消息中心,但用户点击后仅激活应用,不会触发click事件。
为了完整实现,需要在代码中同时监听click事件和receive事件。
wap2app中的推送监听
wap2app应用需要在app.js的onLaunch事件中监听推送消息,本示例接收透传消息,透传消息中包含新闻ID,用户点击推送消息后,直接打开新闻详情,实现消息直达的需求;推送内容如下:
{title:"推送标题",content:"推送内容",payload:{id:1001}}
示例代码如下:
/**
* 当wap2app初始化完成时,会触发 onLaunch
* @param {Object} options
*/
onLaunch: function (options) {
//应用初始化
/******推送消息监听代码开始******/
//监听click事件,用户从消息中心点击触发的
plus.push.addEventListener("click", function (msg) {
console.log("You clicked: " + msg.title); //推送消息标题
console.log("You clicked: " + msg.content); //推送消息内容
//根据payload传递过来的数据,打开一个详情
var payload = msg.payload;
if (payload) {
// payload 按照规范是 Object,但实际推送过来有可能是 String,需要多一步处理;
if (typeof payload === 'string') {
payload = JSON.parse(payload);
}
if (typeof payload === 'object') {
//payload是一个json对象,可以传递业务数据,开发者可以根据实际需求自定义参数
//本示例在payload中传入新闻id,wap2app接收到推送后,直接打开新闻详情
var detailId = payload.id;
//wap2app.open(url)可以直接打开对应的webview
//这里是示例,实际项目中开发者需根据M站的url拼接页面地址
wap2app.open('https://m.example.com/detial/' + detailId + '.html');
}
}
}, false);
//监听receive事件
plus.push.addEventListener("receive", function (msg) {
console.log("recieve title: " + msg.title); //推送消息标题
console.log("recieve content: " + msg.content); //推送消息内容
//根据payload传递过来的数据,打开一个详情
var payload;
if (msg.payload) {
//如透传消息不符合格式,则“payload”属性为string类型
//这里的示例以json字符串去解析,实际上也可以做字符串匹配
if (typeof (msg.payload) == "string") {
try {
payload = JSON.parse(msg.payload);
} catch (error) {
console.log(error);
}
} else if (typeof (msg.payload) == "object") {
//iOS应用正处于前台运行时收到推送,也触发receive事件,此时payload为json对象
payload = msg.payload;
}
if (payload) {
//本示例在payload中传入新闻id,wap2app接收到推送后,直接打开新闻详情
var detailId = payload.id;
//wap2app.open(url)可以直接打开对应的webview
//这里是示例,实际项目中开发者需根据M站的url拼接页面地址
wap2app.open('https://m.example.com/detial/' + detailId + '.html');
}
}
}, false);
/******推送消息监听代码结束******/
} 收起阅读 »
android 指纹识别插件 离线打包版
更新:HTML5+已经自带指纹识别。http://www.html5plus.org/doc/zh_cn/fingerprint.html。以下文档已过期。
安卓问识别插件,需要离线打包才能使用,下面贴上代码:
AndroidManifest.xml 文件
<!--指纹识别权限-->
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
package com.mall.trade.util;
import android.annotation.TargetApi;
import android.app.KeyguardManager;
import android.os.Build;
import android.support.v4.hardware.fingerprint.FingerprintManagerCompat;
import android.support.v4.os.CancellationSignal;
import com.mall.trade.activity.MainActivity;
/**
* Created by Alen on 2017/11/15 0015.
* 指纹识别模块
*/
public class FingerprintUtil {
public static CancellationSignal cancellationSignal;
public static final int DEVICENOTSUPPORTED = 1011;//设备不支持
public static final int DEVICENOTSAFEGUARD = 1012;//设备未处于安全保护中
public static final int DEVICENOTREGUIDFIN = 1013;//设备没有注册过指纹
public static final int SUCCESS = 1000;//支持指纹识别
public static final int FINGETSUCCESS = 1002;//指纹识别成功
public static final int ERROR = 1001;//指纹识别失败
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public static void callFingerPrint(final OnCallBackListenr listener){
FingerprintManagerCompat managerCompat = FingerprintManagerCompat.from(MainActivity.getInstanse());
ResultObj res = checkFingerPrint(managerCompat);//检查指纹识别
if(res.getCode()!=SUCCESS){
if (listener != null){
if(res.getCode()==DEVICENOTSUPPORTED){//判断设备是否支持
listener.onSupportFailed(res);
}else if(res.getCode()==DEVICENOTSAFEGUARD){//判断设备是否处于安全保护中
listener.onInsecurity(res);
}else if(res.getCode()==DEVICENOTSAFEGUARD){//设备没有注册过指纹
listener.onEnrollFailed(res);
}
}
return;
}
if (listener != null)
listener.onAuthenticationStart(res); //开始指纹识别
cancellationSignal = new CancellationSignal(); //必须重新实例化,否则cancel 过一次就不能再使用了
managerCompat.authenticate(null,0,cancellationSignal,new FingerprintManagerCompat.AuthenticationCallback(){
// 当出现错误的时候回调此函数,比如多次尝试都失败了的时候,errString是错误信息,比如华为的提示就是:尝试次数过多,请稍后再试。
@Override
public void onAuthenticationError(int errMsgId, CharSequence errString) {
if (listener != null)
listener.onAuthenticationError(errMsgId ,errString );
}
// 当指纹验证失败的时候会回调此函数,失败之后允许多次尝试,失败次数过多会停止响应一段时间然后再停止sensor的工作
@Override
public void onAuthenticationFailed() {
if (listener != null)
listener.onAuthenticationFailed(new ResultObj(ERROR,"验证失败"));
}
@Override
public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
if (listener != null)
listener.onAuthenticationHelp(helpMsgId,helpString);
}
// 当验证的指纹成功时会回调此函数,然后不再监听指纹sensor
@Override
public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) {
if (listener != null)
listener.onAuthenticationSucceeded(result);
}
;
},null);
}
/**
* 取消指纹识别
*/
public static void cancelFingerPrint(){
if(cancellationSignal!=null){
cancellationSignal.cancel();
}
}
/**
* 判断当前设备是否支持指纹识别
* @return
*/
public static ResultObj checkFingerPrint(){
FingerprintManagerCompat managerCompat = FingerprintManagerCompat.from(MainActivity.getInstanse());
return FingerprintUtil.checkFingerPrint(managerCompat);
}
/**
* 判断当前设备是否支持指纹识别
* @param managerCompat
* @return
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public static ResultObj checkFingerPrint(FingerprintManagerCompat managerCompat){
if (!managerCompat.isHardwareDetected()){ //判断设备是否支持
return new ResultObj(FingerprintUtil.DEVICENOTSUPPORTED,"当前设备不支持指纹");
}
KeyguardManager keyguardManager =(KeyguardManager)MainActivity.getInstanse().getSystemService(MainActivity.getInstanse().KEYGUARD_SERVICE);
if (!keyguardManager.isKeyguardSecure()) {//判断设备是否处于安全保护中
return new ResultObj(FingerprintUtil.DEVICENOTSAFEGUARD,"当前设备没有设置密码保护");
}
if (!managerCompat.hasEnrolledFingerprints()){ //判断设备是否已经注册过指纹
return new ResultObj(FingerprintUtil.DEVICENOTREGUIDFIN,"还没有设置指纹");
}
return new ResultObj(FingerprintUtil.SUCCESS,"支持指纹识别");
}
public interface OnCallBackListenr{
void onSupportFailed(ResultObj error);
void onInsecurity(ResultObj error);
void onEnrollFailed(ResultObj error);
void onAuthenticationStart(ResultObj error);
void onAuthenticationError(int errMsgId, CharSequence errString);
void onAuthenticationFailed(ResultObj error);
void onAuthenticationHelp(int helpMsgId, CharSequence helpString);
void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result);
}
public static class ResultObj{
private int code;
private String msg;
public ResultObj(int code,String msg){
this.code = code;
this.msg = msg;
}
public ResultObj getResult(){
return this;
}
public int getCode(){
return code;
}
public String getMsg(){
return msg;
}
}
public static void cancel(){
if (cancellationSignal != null)
cancellationSignal.cancel();
}
}
下面是调用代码:
/**
* 检查系统是否支持指纹识别
* @param pWebview
* @param array
*/
public void checkFingerPrint(IWebview pWebview, JSONArray array){
String callbackId = array.optString(0);
FingerprintUtil.ResultObj res = FingerprintUtil.checkFingerPrint();
if(res.getCode()==FingerprintUtil.SUCCESS){
String msg = toJSON(res.getCode(), res.getMsg());
Log.d("haiji", "FingerPrint " + res.getCode() + " " + res.getMsg());
JSUtil.execCallback(pWebview,callbackId,msg, JSUtil.OK, false);//成功回调
}else{
Log.d("haiji", "FingerPrint "+res.getMsg());
String error = toJSON(res.getCode(), res.getMsg());
JSUtil.execCallback(pWebview,callbackId,error, JSUtil.ERROR, false);//失败回调
}
}
/**
* 开始进行指纹识别
* @param pWebview
* @param array
*/
public void callFingerPrint(final IWebview pWebview, JSONArray array){
final String callbackId = array.optString(0);
//开始指纹识别
FingerprintUtil.callFingerPrint(new FingerprintUtil.OnCallBackListenr() {
@Override
public void onSupportFailed(FingerprintUtil.ResultObj code) {
String error = toJSON(code.getCode(), code.getMsg());
Log.d("haiji", "FingerPrint "+code.getMsg());
JSUtil.execCallback(pWebview, callbackId, error, JSUtil.ERROR, false);//失败回调
// JsObjectCommonMethod.showToast("当前设备不支持指纹");
}
@Override
public void onInsecurity(FingerprintUtil.ResultObj code) {
String error = toJSON(code.getCode(), code.getMsg());
Log.d("haiji", "FingerPrint "+code.getMsg());
JSUtil.execCallback(pWebview, callbackId, error, JSUtil.ERROR, false);//失败回调
// JsObjectCommonMethod.showToast("当前设备没有设置密码保护");
}
@Override
public void onEnrollFailed(FingerprintUtil.ResultObj code) {
String error = toJSON(code.getCode(), code.getMsg());
Log.d("haiji", "FingerPrint "+code.getMsg());
JSUtil.execCallback(pWebview, callbackId, error, JSUtil.ERROR, false);//失败回调
}
@Override
public void onAuthenticationStart(FingerprintUtil.ResultObj code) {
String error = toJSON(code.getCode(), code.getMsg());
Log.d("haiji", "FingerPrint "+code.getMsg());
JSUtil.execCallback(pWebview, callbackId, error, JSUtil.OK, true);//成功回调
}
@Override
public void onAuthenticationError(int errMsgId, CharSequence errString) {
String error = toJSON(errMsgId, errString.toString());
Log.d("haiji", "FingerPrint "+error.toString());
JSUtil.execCallback(pWebview, callbackId, error, JSUtil.ERROR, false);//失败回调
}
@Override
public void onAuthenticationFailed(FingerprintUtil.ResultObj code) {
String error = toJSON(code.getCode(), code.getMsg());
Log.d("haiji", "FingerPrint "+error);
JSUtil.execCallback(pWebview, callbackId, error, JSUtil.ERROR, false);//失败回调
}
@Override
public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
String error = toJSON(helpMsgId, helpString.toString());
Log.d("haiji", "FingerPrint "+error);
JSUtil.execCallback(pWebview, callbackId, error, JSUtil.ERROR, false);//失败回调
}
@Override
public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) {
String error = toJSON(FingerprintUtil.FINGETSUCCESS, "指纹识别成功");
Log.d("haiji", "FingerPrint "+error);
JSUtil.execCallback(pWebview, callbackId, error, JSUtil.OK, false);//成功回调
}
});
}
/**
* 取消指纹识别
* @param pWebview
* @param array
*/
public void calcelFingerPrint(final IWebview pWebview, JSONArray array){
Log.d("haiji", "FingerPrint 取消指纹识别");
FingerprintUtil.cancelFingerPrint();
}
下面是js中的代码
/**
* 指纹识别检测
* @param param
*/
checkFingerPrint:function(successCbk,errorCbk){
var success = typeof successCbk !== 'function'? null:function(args){
successCbk(args);
}
var fail = typeof errorCbk !== 'function'?null:function(code){
errorCbk(code);
}
callbackID = BRIGE.callbackId(success,fail);
BRIGE.exec(_CLASS_NAME, "checkFingerPrint", [callbackID,""]);
},
/**
* 开始进行指纹识别
* @param param
*/
callFingerPrint:function(successCbk,errorCbk){
var success = typeof successCbk !== 'function'? null:function(args){
successCbk(args);
}
var fail = typeof errorCbk !== 'function'?null:function(code){
errorCbk(code);
}
callbackID = BRIGE.callbackId(success,fail);
BRIGE.exec(_CLASS_NAME, "callFingerPrint", [callbackID,""]);
},
/**
* 取消指纹识别
* @param param
*/
calcelFingerPrint:function(){
BRIGE.exec(_CLASS_NAME, "calcelFingerPrint", []);
}, 更新:HTML5+已经自带指纹识别。http://www.html5plus.org/doc/zh_cn/fingerprint.html。以下文档已过期。
安卓问识别插件,需要离线打包才能使用,下面贴上代码:
AndroidManifest.xml 文件
<!--指纹识别权限-->
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
package com.mall.trade.util;
import android.annotation.TargetApi;
import android.app.KeyguardManager;
import android.os.Build;
import android.support.v4.hardware.fingerprint.FingerprintManagerCompat;
import android.support.v4.os.CancellationSignal;
import com.mall.trade.activity.MainActivity;
/**
* Created by Alen on 2017/11/15 0015.
* 指纹识别模块
*/
public class FingerprintUtil {
public static CancellationSignal cancellationSignal;
public static final int DEVICENOTSUPPORTED = 1011;//设备不支持
public static final int DEVICENOTSAFEGUARD = 1012;//设备未处于安全保护中
public static final int DEVICENOTREGUIDFIN = 1013;//设备没有注册过指纹
public static final int SUCCESS = 1000;//支持指纹识别
public static final int FINGETSUCCESS = 1002;//指纹识别成功
public static final int ERROR = 1001;//指纹识别失败
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public static void callFingerPrint(final OnCallBackListenr listener){
FingerprintManagerCompat managerCompat = FingerprintManagerCompat.from(MainActivity.getInstanse());
ResultObj res = checkFingerPrint(managerCompat);//检查指纹识别
if(res.getCode()!=SUCCESS){
if (listener != null){
if(res.getCode()==DEVICENOTSUPPORTED){//判断设备是否支持
listener.onSupportFailed(res);
}else if(res.getCode()==DEVICENOTSAFEGUARD){//判断设备是否处于安全保护中
listener.onInsecurity(res);
}else if(res.getCode()==DEVICENOTSAFEGUARD){//设备没有注册过指纹
listener.onEnrollFailed(res);
}
}
return;
}
if (listener != null)
listener.onAuthenticationStart(res); //开始指纹识别
cancellationSignal = new CancellationSignal(); //必须重新实例化,否则cancel 过一次就不能再使用了
managerCompat.authenticate(null,0,cancellationSignal,new FingerprintManagerCompat.AuthenticationCallback(){
// 当出现错误的时候回调此函数,比如多次尝试都失败了的时候,errString是错误信息,比如华为的提示就是:尝试次数过多,请稍后再试。
@Override
public void onAuthenticationError(int errMsgId, CharSequence errString) {
if (listener != null)
listener.onAuthenticationError(errMsgId ,errString );
}
// 当指纹验证失败的时候会回调此函数,失败之后允许多次尝试,失败次数过多会停止响应一段时间然后再停止sensor的工作
@Override
public void onAuthenticationFailed() {
if (listener != null)
listener.onAuthenticationFailed(new ResultObj(ERROR,"验证失败"));
}
@Override
public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
if (listener != null)
listener.onAuthenticationHelp(helpMsgId,helpString);
}
// 当验证的指纹成功时会回调此函数,然后不再监听指纹sensor
@Override
public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) {
if (listener != null)
listener.onAuthenticationSucceeded(result);
}
;
},null);
}
/**
* 取消指纹识别
*/
public static void cancelFingerPrint(){
if(cancellationSignal!=null){
cancellationSignal.cancel();
}
}
/**
* 判断当前设备是否支持指纹识别
* @return
*/
public static ResultObj checkFingerPrint(){
FingerprintManagerCompat managerCompat = FingerprintManagerCompat.from(MainActivity.getInstanse());
return FingerprintUtil.checkFingerPrint(managerCompat);
}
/**
* 判断当前设备是否支持指纹识别
* @param managerCompat
* @return
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public static ResultObj checkFingerPrint(FingerprintManagerCompat managerCompat){
if (!managerCompat.isHardwareDetected()){ //判断设备是否支持
return new ResultObj(FingerprintUtil.DEVICENOTSUPPORTED,"当前设备不支持指纹");
}
KeyguardManager keyguardManager =(KeyguardManager)MainActivity.getInstanse().getSystemService(MainActivity.getInstanse().KEYGUARD_SERVICE);
if (!keyguardManager.isKeyguardSecure()) {//判断设备是否处于安全保护中
return new ResultObj(FingerprintUtil.DEVICENOTSAFEGUARD,"当前设备没有设置密码保护");
}
if (!managerCompat.hasEnrolledFingerprints()){ //判断设备是否已经注册过指纹
return new ResultObj(FingerprintUtil.DEVICENOTREGUIDFIN,"还没有设置指纹");
}
return new ResultObj(FingerprintUtil.SUCCESS,"支持指纹识别");
}
public interface OnCallBackListenr{
void onSupportFailed(ResultObj error);
void onInsecurity(ResultObj error);
void onEnrollFailed(ResultObj error);
void onAuthenticationStart(ResultObj error);
void onAuthenticationError(int errMsgId, CharSequence errString);
void onAuthenticationFailed(ResultObj error);
void onAuthenticationHelp(int helpMsgId, CharSequence helpString);
void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result);
}
public static class ResultObj{
private int code;
private String msg;
public ResultObj(int code,String msg){
this.code = code;
this.msg = msg;
}
public ResultObj getResult(){
return this;
}
public int getCode(){
return code;
}
public String getMsg(){
return msg;
}
}
public static void cancel(){
if (cancellationSignal != null)
cancellationSignal.cancel();
}
}
下面是调用代码:
/**
* 检查系统是否支持指纹识别
* @param pWebview
* @param array
*/
public void checkFingerPrint(IWebview pWebview, JSONArray array){
String callbackId = array.optString(0);
FingerprintUtil.ResultObj res = FingerprintUtil.checkFingerPrint();
if(res.getCode()==FingerprintUtil.SUCCESS){
String msg = toJSON(res.getCode(), res.getMsg());
Log.d("haiji", "FingerPrint " + res.getCode() + " " + res.getMsg());
JSUtil.execCallback(pWebview,callbackId,msg, JSUtil.OK, false);//成功回调
}else{
Log.d("haiji", "FingerPrint "+res.getMsg());
String error = toJSON(res.getCode(), res.getMsg());
JSUtil.execCallback(pWebview,callbackId,error, JSUtil.ERROR, false);//失败回调
}
}
/**
* 开始进行指纹识别
* @param pWebview
* @param array
*/
public void callFingerPrint(final IWebview pWebview, JSONArray array){
final String callbackId = array.optString(0);
//开始指纹识别
FingerprintUtil.callFingerPrint(new FingerprintUtil.OnCallBackListenr() {
@Override
public void onSupportFailed(FingerprintUtil.ResultObj code) {
String error = toJSON(code.getCode(), code.getMsg());
Log.d("haiji", "FingerPrint "+code.getMsg());
JSUtil.execCallback(pWebview, callbackId, error, JSUtil.ERROR, false);//失败回调
// JsObjectCommonMethod.showToast("当前设备不支持指纹");
}
@Override
public void onInsecurity(FingerprintUtil.ResultObj code) {
String error = toJSON(code.getCode(), code.getMsg());
Log.d("haiji", "FingerPrint "+code.getMsg());
JSUtil.execCallback(pWebview, callbackId, error, JSUtil.ERROR, false);//失败回调
// JsObjectCommonMethod.showToast("当前设备没有设置密码保护");
}
@Override
public void onEnrollFailed(FingerprintUtil.ResultObj code) {
String error = toJSON(code.getCode(), code.getMsg());
Log.d("haiji", "FingerPrint "+code.getMsg());
JSUtil.execCallback(pWebview, callbackId, error, JSUtil.ERROR, false);//失败回调
}
@Override
public void onAuthenticationStart(FingerprintUtil.ResultObj code) {
String error = toJSON(code.getCode(), code.getMsg());
Log.d("haiji", "FingerPrint "+code.getMsg());
JSUtil.execCallback(pWebview, callbackId, error, JSUtil.OK, true);//成功回调
}
@Override
public void onAuthenticationError(int errMsgId, CharSequence errString) {
String error = toJSON(errMsgId, errString.toString());
Log.d("haiji", "FingerPrint "+error.toString());
JSUtil.execCallback(pWebview, callbackId, error, JSUtil.ERROR, false);//失败回调
}
@Override
public void onAuthenticationFailed(FingerprintUtil.ResultObj code) {
String error = toJSON(code.getCode(), code.getMsg());
Log.d("haiji", "FingerPrint "+error);
JSUtil.execCallback(pWebview, callbackId, error, JSUtil.ERROR, false);//失败回调
}
@Override
public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
String error = toJSON(helpMsgId, helpString.toString());
Log.d("haiji", "FingerPrint "+error);
JSUtil.execCallback(pWebview, callbackId, error, JSUtil.ERROR, false);//失败回调
}
@Override
public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) {
String error = toJSON(FingerprintUtil.FINGETSUCCESS, "指纹识别成功");
Log.d("haiji", "FingerPrint "+error);
JSUtil.execCallback(pWebview, callbackId, error, JSUtil.OK, false);//成功回调
}
});
}
/**
* 取消指纹识别
* @param pWebview
* @param array
*/
public void calcelFingerPrint(final IWebview pWebview, JSONArray array){
Log.d("haiji", "FingerPrint 取消指纹识别");
FingerprintUtil.cancelFingerPrint();
}
下面是js中的代码
/**
* 指纹识别检测
* @param param
*/
checkFingerPrint:function(successCbk,errorCbk){
var success = typeof successCbk !== 'function'? null:function(args){
successCbk(args);
}
var fail = typeof errorCbk !== 'function'?null:function(code){
errorCbk(code);
}
callbackID = BRIGE.callbackId(success,fail);
BRIGE.exec(_CLASS_NAME, "checkFingerPrint", [callbackID,""]);
},
/**
* 开始进行指纹识别
* @param param
*/
callFingerPrint:function(successCbk,errorCbk){
var success = typeof successCbk !== 'function'? null:function(args){
successCbk(args);
}
var fail = typeof errorCbk !== 'function'?null:function(code){
errorCbk(code);
}
callbackID = BRIGE.callbackId(success,fail);
BRIGE.exec(_CLASS_NAME, "callFingerPrint", [callbackID,""]);
},
/**
* 取消指纹识别
* @param param
*/
calcelFingerPrint:function(){
BRIGE.exec(_CLASS_NAME, "calcelFingerPrint", []);
}, 收起阅读 »
【分享】【开源】canvas图像裁剪、压缩、旋转
前言
前段时间遇到了一个移动端对图像进行裁剪、压缩、旋转的需求。
考虑到已有各轮子的契合度都不高,于是自己重新造了一个轮子。
关于图像裁剪、压缩
在HTML5时代,canvas的功能已经非常强大了,可以进行像素级的操作。像图像裁剪、压缩就都是基于canvas来实现的。
关于其中原理,无非就是利用canvas自带的API,复杂一点的就是裁剪框以及旋转后的坐标计算,因此不再赘述。
本文中的图像裁剪、压缩都是基于canvas完成的。
图像裁剪
功能包括:
-
canvas绘制图片
-
裁剪框选择裁剪大小
-
旋转功能
-
放大镜(方便旋转)
-
裁剪功能
-
缩放、压缩功能(通过参数控制)
示例
https://dailc.github.io/image-process/examples/clip.html
效果




[图片上传失败...(image-c687d7-1510800462845)]
使用
引入
dist/image-clip.css
dist/image-clip.js
全局变量
ImageClip
调用方法
var cropImage = new ImageClip(options);
cropImage.method()
API
resetClipRect
重置裁剪框,重新变为最大
cropImage.resetClipRect();
clip
裁剪图像,根据当前的裁剪框进行裁剪
cropImage.clip();
getClipImgData
获取已裁剪的图像
var base64 = cropImage.getClipImgData();
rotate
旋转图片
cropImage.clip(isClockWise);
destroy
销毁当前的裁剪对象
如果一个容器需要重新生成裁剪对象,一定要先销毁以前的
cropImage.destroy();
更多
关于详细参数说明与更多使用
请参考源码
图像缩放
上述的图片裁剪中其实已经附带缩放功能,但是鉴于那是基于整套裁剪流程的,不满足一些场景(譬如只要针对图片压缩的)。
因此,单独又将图像缩放提取成一个模块,以适用于此类场景。
功能包括:
-
图像的缩放、压缩
-
一些常用的缩放算法(双立方,双线性,近邻)
示例
https://dailc.github.io/image-process/examples/scale.html
https://dailc.github.io/image-process/examples/scale_compress.html
效果
示例较为粗糙
使用
引入
dist/image-scale.js
全局变量
ImageScale
调用方法
ImageScale.method()
API
scaleImageData
对ImageData类型的数据进行缩放,将数据放入新的ImageData中
ImageScale.scaleImageData(imageData, newImageData, {
// 0: nearestNeighbor
// 1: bilinearInterpolation
// 2: bicubicInterpolation
// 3: bicubicInterpolation2
processType: 0,
});
scaleImage
对Image类型的对象进行缩放,返回一个base64字符串
var base64 = ImageScale.scaleImage(image, {
width: 80,
height: 80,
mime: 'image/png',
// 0: nearestNeighbor
// 1: bilinearInterpolation
// 2: bicubicInterpolation
// 3: bicubicInterpolation2
processType: 0,
});
compressImage
compressImage,返回一个base64字符串
与scale的区别是这用的是canvas自动缩放,并且有很多参数可控
var base64 = ImageScale.compressImage(image, {
// 压缩质量
quality: 0.92,
mime: 'image/jpeg',
// 压缩时的放大系数,默认为1,如果增大,代表图像的尺寸会变大(最大不会超过原图)
compressScaleRatio: 1,
// ios的iPhone下主动放大一定系数以解决分辨率过小的模糊问题
iphoneFixedRatio: 2,
// 是否采用原图像素(不会改变大小)
isUseOriginSize: false,
// 增加最大宽度,增加后最大不会超过这个宽度
maxWidth: 0,
// 使用强制的宽度,如果使用,其它宽高比系数都会失效,默认整图使用这个宽度
forceWidth: 0,
// 同上,但是一般不建议设置,因为很可能会改变宽高比导致拉升,特殊场景下使用
forceHeight: 0,
});
更多
关于详细参数说明与更多使用
请参考源码
完善与不足
虽然说一些注意的功能都已经实现,但是从细节角度考虑,还是有很多有待完善的地方的。
譬如,裁剪框的实现方式不优雅。
譬如,旋转不支持其它角度。
譬如,内部源码有待优化。
...
虽然说有计划未来某段时间重构,但考虑到实际的时间安排,可能得等到很后了。
源码
图像裁剪:
https://github.com/dailc/image-process/blob/master/src/clip/README.md
图像缩放:
https://github.com/dailc/image-process/blob/master/src/scale/README.md
前言
前段时间遇到了一个移动端对图像进行裁剪、压缩、旋转的需求。
考虑到已有各轮子的契合度都不高,于是自己重新造了一个轮子。
关于图像裁剪、压缩
在HTML5时代,canvas的功能已经非常强大了,可以进行像素级的操作。像图像裁剪、压缩就都是基于canvas来实现的。
关于其中原理,无非就是利用canvas自带的API,复杂一点的就是裁剪框以及旋转后的坐标计算,因此不再赘述。
本文中的图像裁剪、压缩都是基于canvas完成的。
图像裁剪
功能包括:
-
canvas绘制图片
-
裁剪框选择裁剪大小
-
旋转功能
-
放大镜(方便旋转)
-
裁剪功能
-
缩放、压缩功能(通过参数控制)
示例
https://dailc.github.io/image-process/examples/clip.html
效果




[图片上传失败...(image-c687d7-1510800462845)]
使用
引入
dist/image-clip.css
dist/image-clip.js
全局变量
ImageClip
调用方法
var cropImage = new ImageClip(options);
cropImage.method()
API
resetClipRect
重置裁剪框,重新变为最大
cropImage.resetClipRect();
clip
裁剪图像,根据当前的裁剪框进行裁剪
cropImage.clip();
getClipImgData
获取已裁剪的图像
var base64 = cropImage.getClipImgData();
rotate
旋转图片
cropImage.clip(isClockWise);
destroy
销毁当前的裁剪对象
如果一个容器需要重新生成裁剪对象,一定要先销毁以前的
cropImage.destroy();
更多
关于详细参数说明与更多使用
请参考源码
图像缩放
上述的图片裁剪中其实已经附带缩放功能,但是鉴于那是基于整套裁剪流程的,不满足一些场景(譬如只要针对图片压缩的)。
因此,单独又将图像缩放提取成一个模块,以适用于此类场景。
功能包括:
-
图像的缩放、压缩
-
一些常用的缩放算法(双立方,双线性,近邻)
示例
https://dailc.github.io/image-process/examples/scale.html
https://dailc.github.io/image-process/examples/scale_compress.html
效果
示例较为粗糙
使用
引入
dist/image-scale.js
全局变量
ImageScale
调用方法
ImageScale.method()
API
scaleImageData
对ImageData类型的数据进行缩放,将数据放入新的ImageData中
ImageScale.scaleImageData(imageData, newImageData, {
// 0: nearestNeighbor
// 1: bilinearInterpolation
// 2: bicubicInterpolation
// 3: bicubicInterpolation2
processType: 0,
});
scaleImage
对Image类型的对象进行缩放,返回一个base64字符串
var base64 = ImageScale.scaleImage(image, {
width: 80,
height: 80,
mime: 'image/png',
// 0: nearestNeighbor
// 1: bilinearInterpolation
// 2: bicubicInterpolation
// 3: bicubicInterpolation2
processType: 0,
});
compressImage
compressImage,返回一个base64字符串
与scale的区别是这用的是canvas自动缩放,并且有很多参数可控
var base64 = ImageScale.compressImage(image, {
// 压缩质量
quality: 0.92,
mime: 'image/jpeg',
// 压缩时的放大系数,默认为1,如果增大,代表图像的尺寸会变大(最大不会超过原图)
compressScaleRatio: 1,
// ios的iPhone下主动放大一定系数以解决分辨率过小的模糊问题
iphoneFixedRatio: 2,
// 是否采用原图像素(不会改变大小)
isUseOriginSize: false,
// 增加最大宽度,增加后最大不会超过这个宽度
maxWidth: 0,
// 使用强制的宽度,如果使用,其它宽高比系数都会失效,默认整图使用这个宽度
forceWidth: 0,
// 同上,但是一般不建议设置,因为很可能会改变宽高比导致拉升,特殊场景下使用
forceHeight: 0,
});
更多
关于详细参数说明与更多使用
请参考源码
完善与不足
虽然说一些注意的功能都已经实现,但是从细节角度考虑,还是有很多有待完善的地方的。
譬如,裁剪框的实现方式不优雅。
譬如,旋转不支持其它角度。
譬如,内部源码有待优化。
...
虽然说有计划未来某段时间重构,但考虑到实际的时间安排,可能得等到很后了。
源码
图像裁剪:
https://github.com/dailc/image-process/blob/master/src/clip/README.md
图像缩放:
https://github.com/dailc/image-process/blob/master/src/scale/README.md
收起阅读 »






