
uniapp px转upx 自动转换方法
修改less插件实现px转upx
1、安装插件 less
2、找到HBuilderX\plugins\compile-less\node_modules\less\lib\less\parse.js

input=input.replace(/\b(\d+(.\d+)?)px\b/ig, "$1upx")//替换upx
添加一行正则转换规则
保存会提示没有权限修改文件权限在保存就ok了
修改less插件实现px转upx
1、安装插件 less
2、找到HBuilderX\plugins\compile-less\node_modules\less\lib\less\parse.js
input=input.replace(/\b(\d+(.\d+)?)px\b/ig, "$1upx")//替换upx
添加一行正则转换规则
保存会提示没有权限修改文件权限在保存就ok了
收起阅读 »
iOS上架元数据被拒相关问题解答
注意:元素数据被拒绝不需要重新打包上传ipa,修改问题后回复即可!
iOS APP上架被拒重新提交审核教程
http://www.applicationloader.net/blog/zh/1431.html
关于元数据被拒绝(元数据名称、描述、评级、排名等)
1. 应用或者元数据中提到其他任何移动平台都将会被拒绝。
2. 带有占位符文本的应用将会被拒绝
3. 应用程序的名称、描述、截图或者预览与应用的内容和功能不相关将会被拒绝。
4. 为了不让用户产生困惑,iTunes Connect中的应用名称应该和展示在设备上的应用名称一致。
5. 应用的大图标和小图标要一致,以免造成混淆。
6. 图标、截图以及预览以及当Apple TV应用被展示在Apple TV主界面顶部的时候不符合4+年龄评级的应用将会被拒绝。7. 分类与内容选择不适合应用内容的程序将会被拒绝。
8. 开发者有责任为其程序指定适合的评级。不恰当的评级可能会由苹果公司进行修改或者删除。9. 开发者有责任为其应用指定恰当的关键字。不恰当的关键词可能会被苹果公司修改或删除。
10. 试图操控或者欺骗用户评价,或使用虚假/付费购买评价的方式在App Store排行榜作弊,或者采用其他不正当方式)以提升排名的开发者将会被苹果从iOS开发者项目中除名。
11. 在安装或打开之前,推荐用户重启iOS设备的应用将会被拒绝。
12. 提交审核的所有应用都应包含能正常运行的URL,比如支持服务URL和私有政策URL。
13. 应用程序的截图、预览或者营销文本没有清晰地指出附加内容或项目需要额外单独购买(比如使用IAP)将会被拒绝。
14. App预览只能是使用应用本身捕捉的视频、旁白、文本以及设计轮廓,否则应用将会被拒绝。
15. 在未经允许的情况下展示真实个人信息的应用将会被拒绝。16. 应用预览只能使用在所有选定地区内经过授权许可的音乐。
17. 包含未经授权而把应用播放或者直播内容(比如音乐、视频和相关封面艺术)用作预览或者截屏的应用将会被拒绝。注意提供用户名和密码的准确性。注意仔细检查产品给你提供上传浏览图片的内容。
注意:元素数据被拒绝不需要重新打包上传ipa,修改问题后回复即可!
iOS APP上架被拒重新提交审核教程
http://www.applicationloader.net/blog/zh/1431.html
关于元数据被拒绝(元数据名称、描述、评级、排名等)
1. 应用或者元数据中提到其他任何移动平台都将会被拒绝。
2. 带有占位符文本的应用将会被拒绝
3. 应用程序的名称、描述、截图或者预览与应用的内容和功能不相关将会被拒绝。
4. 为了不让用户产生困惑,iTunes Connect中的应用名称应该和展示在设备上的应用名称一致。
5. 应用的大图标和小图标要一致,以免造成混淆。
6. 图标、截图以及预览以及当Apple TV应用被展示在Apple TV主界面顶部的时候不符合4+年龄评级的应用将会被拒绝。7. 分类与内容选择不适合应用内容的程序将会被拒绝。
8. 开发者有责任为其程序指定适合的评级。不恰当的评级可能会由苹果公司进行修改或者删除。9. 开发者有责任为其应用指定恰当的关键字。不恰当的关键词可能会被苹果公司修改或删除。
10. 试图操控或者欺骗用户评价,或使用虚假/付费购买评价的方式在App Store排行榜作弊,或者采用其他不正当方式)以提升排名的开发者将会被苹果从iOS开发者项目中除名。
11. 在安装或打开之前,推荐用户重启iOS设备的应用将会被拒绝。
12. 提交审核的所有应用都应包含能正常运行的URL,比如支持服务URL和私有政策URL。
13. 应用程序的截图、预览或者营销文本没有清晰地指出附加内容或项目需要额外单独购买(比如使用IAP)将会被拒绝。
14. App预览只能是使用应用本身捕捉的视频、旁白、文本以及设计轮廓,否则应用将会被拒绝。
15. 在未经允许的情况下展示真实个人信息的应用将会被拒绝。16. 应用预览只能使用在所有选定地区内经过授权许可的音乐。
17. 包含未经授权而把应用播放或者直播内容(比如音乐、视频和相关封面艺术)用作预览或者截屏的应用将会被拒绝。注意提供用户名和密码的准确性。注意仔细检查产品给你提供上传浏览图片的内容。
收起阅读 »
自定义基座不生成安装包
最近因为要调试自定义的原生插件,于是尝试使用自定义基座,结果点了好多遍都诶有生成自定义基座的安装包,在unpackage-->debug目录下会生成安装和ios的安装包。由于本人习惯问题,把ios的选项给去掉了,而且下面什么渠道包、广告联盟啥的全都取消了,只留了一个自定义基座,可是试了很多次都没有生成基座的安装包。一直没找到是什么原因,后来不经意间把ios什么的框框全都勾上了,一点打包居然生成出了基座的安装包,真是搞不懂什么原因。如果有遇到类似问题的可以试试把所有的勾都勾上在打包。
还有必须要吐槽的就是,制作自定义基座也会把项目提交到服务器打包,不知道是什么原因不能单独制作基座安装包,这样不是浪费服务器资源吗?
自定义基座生成成功的日志应该是这样的,前几次没有生成成功都是直接把项目上传打包了,返回了项目的下载地址(只能下载5次的那个地址)
最近因为要调试自定义的原生插件,于是尝试使用自定义基座,结果点了好多遍都诶有生成自定义基座的安装包,在unpackage-->debug目录下会生成安装和ios的安装包。由于本人习惯问题,把ios的选项给去掉了,而且下面什么渠道包、广告联盟啥的全都取消了,只留了一个自定义基座,可是试了很多次都没有生成基座的安装包。一直没找到是什么原因,后来不经意间把ios什么的框框全都勾上了,一点打包居然生成出了基座的安装包,真是搞不懂什么原因。如果有遇到类似问题的可以试试把所有的勾都勾上在打包。
还有必须要吐槽的就是,制作自定义基座也会把项目提交到服务器打包,不知道是什么原因不能单独制作基座安装包,这样不是浪费服务器资源吗?
自定义基座生成成功的日志应该是这样的,前几次没有生成成功都是直接把项目上传打包了,返回了项目的下载地址(只能下载5次的那个地址) 收起阅读 »

uni-app 在APP-PLUS下实现mdns自动发现同网段设备服务
//#ifdef APP-PLUS //条件编译
let vm = this;
let mServerType = '_http._tcp.';//服务类型
let NsdServiceInfo = plus.android.importClass('android.net.nsd.NsdServiceInfo');
let NsdManager = plus.android.importClass('android.net.nsd.NsdManager');
let Context = plus.android.importClass('android.content.Context');
// 导入后可以使用new方法创建类的实例对象
let nsd_service_info = new NsdServiceInfo();
let nsd_manager = new NsdManager();
//获取应用主Activity实例对象系统服务NSD_SERVICE方法
let mNsdManager = plus.android.runtimeMainActivity().getSystemService(Context.NSD_SERVICE);
//实列API接口监听回调函数
let mDiscoveryListener = plus.android.implements('android.net.nsd.NsdManager$DiscoveryListener', {
onServiceFound: function(service) {
//先发现设备服务再执行连接获取数据
//导入service类
plus.android.importClass(service);
//实列化连接服务接口监听回调函数
//注意NsdManager$ResolveListener中间使用$不是“.”
let mResolveListener = plus.android.implements('android.net.nsd.NsdManager$ResolveListener', {
onServiceResolved: function(services) {
//连接服务
let name = services.getServiceName();
let port = services.getPort();
let ip = services.getHost();
plus.android.importClass(ip); //导入services.getHost()类
ip = ip.getHostAddress();
let arry = {
name: name,
port: port,
ip: ip
};
}
});
mNsdManager.resolveService(service, mResolveListener);//启动连接服务
}
});
// 导入mNsdManager Java类对象
plus.android.importClass(mNsdManager);
mNsdManager.discoverServices(mServerType, 1, mDiscoveryListener);//启动监听服务(类型,常量,回调函数)参考java discoverServices需要携带的参数类型
//#endif
plus调用安卓所有原生大致实现方法:
1.let NsdServiceInfo= plus.android.importClass("java类")
2.let nsd_service_info= new NsdServiceInfo() new方法创建类的实例对象
3.let mNsdManager = plus.android.runtimeMainActivity().getSystemService(Context.NSD_SERVICE); //获取应用主Activity实例对象系统服务NSD_SERVICE方法
4.plus.android.implements 声明监听回调方法 (主要通过监听函数获取数据)
5.mNsdManager.discoverServices(mServerType, 1, mDiscoveryListener);//启动监听服务
https://android.googlesource.com/platform/development/+/master/samples/training/NsdChat/src/com/example/android/nsdchat/NsdHelper.java 需要引入的类和整个实现方法参考java源代码
//#ifdef APP-PLUS //条件编译
let vm = this;
let mServerType = '_http._tcp.';//服务类型
let NsdServiceInfo = plus.android.importClass('android.net.nsd.NsdServiceInfo');
let NsdManager = plus.android.importClass('android.net.nsd.NsdManager');
let Context = plus.android.importClass('android.content.Context');
// 导入后可以使用new方法创建类的实例对象
let nsd_service_info = new NsdServiceInfo();
let nsd_manager = new NsdManager();
//获取应用主Activity实例对象系统服务NSD_SERVICE方法
let mNsdManager = plus.android.runtimeMainActivity().getSystemService(Context.NSD_SERVICE);
//实列API接口监听回调函数
let mDiscoveryListener = plus.android.implements('android.net.nsd.NsdManager$DiscoveryListener', {
onServiceFound: function(service) {
//先发现设备服务再执行连接获取数据
//导入service类
plus.android.importClass(service);
//实列化连接服务接口监听回调函数
//注意NsdManager$ResolveListener中间使用$不是“.”
let mResolveListener = plus.android.implements('android.net.nsd.NsdManager$ResolveListener', {
onServiceResolved: function(services) {
//连接服务
let name = services.getServiceName();
let port = services.getPort();
let ip = services.getHost();
plus.android.importClass(ip); //导入services.getHost()类
ip = ip.getHostAddress();
let arry = {
name: name,
port: port,
ip: ip
};
}
});
mNsdManager.resolveService(service, mResolveListener);//启动连接服务
}
});
// 导入mNsdManager Java类对象
plus.android.importClass(mNsdManager);
mNsdManager.discoverServices(mServerType, 1, mDiscoveryListener);//启动监听服务(类型,常量,回调函数)参考java discoverServices需要携带的参数类型
//#endif
plus调用安卓所有原生大致实现方法:
1.let NsdServiceInfo= plus.android.importClass("java类")
2.let nsd_service_info= new NsdServiceInfo() new方法创建类的实例对象
3.let mNsdManager = plus.android.runtimeMainActivity().getSystemService(Context.NSD_SERVICE); //获取应用主Activity实例对象系统服务NSD_SERVICE方法
4.plus.android.implements 声明监听回调方法 (主要通过监听函数获取数据)
5.mNsdManager.discoverServices(mServerType, 1, mDiscoveryListener);//启动监听服务
https://android.googlesource.com/platform/development/+/master/samples/training/NsdChat/src/com/example/android/nsdchat/NsdHelper.java 需要引入的类和整个实现方法参考java源代码
收起阅读 »
安卓环境下应用签名校验,解决【应用签名未校验风险】
由于业务需要,公司对App进行了第三方安全评估,发现了【应用签名未校验风险】,而且风险等级为【高】,老板看了说一定要解决,“拿人钱财,替人消灾”,开干!。
以下代码已在安卓6.0和安卓9.0手机上测试通过。
//如果是安卓运行环境,校验应用签名是否正确
if(plus.os.name=='Android'){
if(!checkApkSign('SHA1')){
$.alert('签名异常,请到各大应用市场下载安装正版XXXX。','错误',function (e) {
plus.runtime.quit();
});
}
}
/**
* 检查安卓APK签名
* @param {String} type 签名指纹类型:MD5或SHA1
*/
function checkApkSign(type){
//获取应用上下文
var context = plus.android.runtimeMainActivity();
var PackageManager = plus.android.importClass("android.content.pm.PackageManager");
var packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(),PackageManager.GET_SIGNING_CERTIFICATES||PackageManager.GET_SIGNATURES)
var Build = plus.android.importClass("android.os.Build");
var signatures = null;
//Android 28以后获取包签名信息方法改了
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.P){
var signingInfo = packageInfo.plusGetAttribute('signingInfo');
signatures = plus.android.invoke(signingInfo,"getApkContentsSigners")
}else{
signatures = packageInfo.plusGetAttribute('signatures');
}
if (signatures != null) {
var signature;
var byteArr;
var currentSignature;
var md = plus.android.invoke("java.security.MessageDigest","getInstance",type);
for (var i in signatures) {
byteArr=plus.android.invoke(signatures[i],"toByteArray");
plus.android.invoke(md,"update",byteArr);
currentSignature = Bytes2HexString(plus.android.invoke(md,"digest")).toUpperCase();
//根据检验类型,与与你签名文件对应的签名值比对
if(("SHA1"==type && "你签名的SHA1值"==currentSignature)
|| ("MD5"==type &&"你签名的MD5值"==currentSignature)){
return true;
}
}
} else {
console.info("应用未签名");
}
return false;
}
//字节数组转十六进制字符串,对负值填坑
function Bytes2HexString(arrBytes) {
var str = "";
for (var i = 0; i < arrBytes.length; i++) {
var tmp;
var num=arrBytes[i];
if (num < 0) {
//此处填坑,当byte因为符合位导致数值为负时候,需要对数据进行处理
tmp =(255+num+1).toString(16);
} else {
tmp = num.toString(16);
}
if (tmp.length == 1) {
tmp = "0" + tmp;
}
str += tmp;
}
return str;
}
由于业务需要,公司对App进行了第三方安全评估,发现了【应用签名未校验风险】,而且风险等级为【高】,老板看了说一定要解决,“拿人钱财,替人消灾”,开干!。
以下代码已在安卓6.0和安卓9.0手机上测试通过。
//如果是安卓运行环境,校验应用签名是否正确
if(plus.os.name=='Android'){
if(!checkApkSign('SHA1')){
$.alert('签名异常,请到各大应用市场下载安装正版XXXX。','错误',function (e) {
plus.runtime.quit();
});
}
}
/**
* 检查安卓APK签名
* @param {String} type 签名指纹类型:MD5或SHA1
*/
function checkApkSign(type){
//获取应用上下文
var context = plus.android.runtimeMainActivity();
var PackageManager = plus.android.importClass("android.content.pm.PackageManager");
var packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(),PackageManager.GET_SIGNING_CERTIFICATES||PackageManager.GET_SIGNATURES)
var Build = plus.android.importClass("android.os.Build");
var signatures = null;
//Android 28以后获取包签名信息方法改了
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.P){
var signingInfo = packageInfo.plusGetAttribute('signingInfo');
signatures = plus.android.invoke(signingInfo,"getApkContentsSigners")
}else{
signatures = packageInfo.plusGetAttribute('signatures');
}
if (signatures != null) {
var signature;
var byteArr;
var currentSignature;
var md = plus.android.invoke("java.security.MessageDigest","getInstance",type);
for (var i in signatures) {
byteArr=plus.android.invoke(signatures[i],"toByteArray");
plus.android.invoke(md,"update",byteArr);
currentSignature = Bytes2HexString(plus.android.invoke(md,"digest")).toUpperCase();
//根据检验类型,与与你签名文件对应的签名值比对
if(("SHA1"==type && "你签名的SHA1值"==currentSignature)
|| ("MD5"==type &&"你签名的MD5值"==currentSignature)){
return true;
}
}
} else {
console.info("应用未签名");
}
return false;
}
//字节数组转十六进制字符串,对负值填坑
function Bytes2HexString(arrBytes) {
var str = "";
for (var i = 0; i < arrBytes.length; i++) {
var tmp;
var num=arrBytes[i];
if (num < 0) {
//此处填坑,当byte因为符合位导致数值为负时候,需要对数据进行处理
tmp =(255+num+1).toString(16);
} else {
tmp = num.toString(16);
}
if (tmp.length == 1) {
tmp = "0" + tmp;
}
str += tmp;
}
return str;
}
收起阅读 »

关于WAP2APP打包JS混淆加密的方法(防止解压直接查看源码)
加密目的是为了防止别人解压APP文件后既可拿到你的信息和源代码,保护APP信息安全。
第一步,点击WAP2APP项目的manifest.json然后点击源码视图找到plus节点添加如下加密代码配置好后保存:
"confusion" : {
"description" : "js原生混淆配置",
"resources" : {
"js/share.js" : {}, //列如加密的路径文件地址js/share.js
"sitemap.json" : {}
}
},
如下图:
第二步,发行原生APP-云打包的时候,务必要勾选启用JS原生混淆然后点击打包既可生效。如下图:
这样就大功告成了,别人解压也看不到你的APP代码了,包括sitemap.json文件信息别人也看不到了。
HX的JS混淆加密功能是非常强大的。
加密目的是为了防止别人解压APP文件后既可拿到你的信息和源代码,保护APP信息安全。
第一步,点击WAP2APP项目的manifest.json然后点击源码视图找到plus节点添加如下加密代码配置好后保存:
"confusion" : {
"description" : "js原生混淆配置",
"resources" : {
"js/share.js" : {}, //列如加密的路径文件地址js/share.js
"sitemap.json" : {}
}
},
如下图:
第二步,发行原生APP-云打包的时候,务必要勾选启用JS原生混淆然后点击打包既可生效。如下图:
这样就大功告成了,别人解压也看不到你的APP代码了,包括sitemap.json文件信息别人也看不到了。
HX的JS混淆加密功能是非常强大的。
收起阅读 »
uni-app中使用阿里云MQTT,Dome分享,仅限APP端
var $mqtt = require("@/common/js/mqttws31.js");
var $crypto = require("@/common/js/crypto-js.js");
var instanceId = 'xxxxxxxxxx'; //实例 ID,购买后从控制台获取
var host = 'xxxxxxxxxx.mqtt.aliyuncs.com'; // 设置当前用户的接入点域名,接入点获取方法请参考接入准备章节文档,先在控制台创建实例
var port = 80; //WebSocket 协议服务端口,如果是走 HTTPS,设置443端口
var topic = 'Topic_xxxxxxxxxx'; //需要操作的 Topic,第一级父级 topic 需要在控制台申请
var useTLS = false; //是否走加密 HTTPS,如果走 HTTPS,设置为 true
var accessKey = 'xxxxxxxxxx'; //账号的 AccessKey,在阿里云控制台查看
var secretKey = 'xxxxxxxxxx'; //账号的的 SecretKey,在阿里云控制台查看
var cleansession = true;
var groupId = 'GID_xxxxxxxxxx'; //MQTT GroupID,创建实例后从 MQTT 控制台创建
var clientId = groupId '@@@00001'; //GroupId@@@DeviceId,由控制台创建的 Group ID 和自己指定的 Device ID 组合构成
var mqtt;
var reconnectTimeout = 2000;
var username = 'Signature|' accessKey '|' instanceId; //username和 Password 签名模式下的设置方法,参考文档 https://help.aliyun.com/document_detail/48271.html?spm=a2c4g.11186623.6.553.217831c3BSFry7
var password = "";
export default {
data() {
return {
mecont: []
}
},
onLoad() {
password = $crypto.HmacSHA1(clientId, secretKey).toString($crypto.enc.Base64);
MQTTconnect(this);
},
methods: {
}
}
function MQTTconnect(_this) {
mqtt = new $mqtt.Client(
host, //MQTT 域名
port, //WebSocket 端口,如果使用 HTTPS 加密则配置为443,否则配置80
clientId //客户端 ClientId
);
var options = {
userName: username,
password: password,
useSSL: useTLS, //如果使用 HTTPS 加密则配置为 true
onSuccess: function onConnect() { //连接成功
_this.mecont.push(new Date() ": " "连接成功");
// Connection succeeded; subscribe to our topic
//订阅消息
mqtt.subscribe(topic "/subDemo1", {
qos: 0
});
//测试消息推送
var message = new $mqtt.Message("APP测试消息推送!!"); //set body
message.destinationName = topic; // set topic
// //发送 P2P 消息,topic 设置方式参考https://help.aliyun.com/document_detail/96176.html?spm=a2c4g.11186623.6.586.694f7cb4oookL7
// message = new $mqtt.Message("Hello mqtt P2P Msg!!"); //set body
// message.destinationName = topic "/p2p/" clientId; // set topic
mqtt.send(message);
},
onFailure: function(message) { //连接失败
_this.mecont.push(new Date() ": " "连接失败" JSON.stringify(message));
//连接失败,重新连接
setTimeout(MQTTconnect, reconnectTimeout);
}
};
mqtt.onConnectionLost = function onConnectionLost(response) {
_this.mecont.push(new Date() ": " "连接中断" JSON.stringify(response));
//连接失败,重新连接
setTimeout(MQTTconnect, reconnectTimeout);
};
mqtt.onMessageArrived = function onMessageArrived(message) {
var topic = message.destinationName;
var payload = message.payloadString;
_this.mecont.push(new Date() ": " "收到新消息" topic " " payload);
};
mqtt.connect(options);
}
var $mqtt = require("@/common/js/mqttws31.js");
var $crypto = require("@/common/js/crypto-js.js");
var instanceId = 'xxxxxxxxxx'; //实例 ID,购买后从控制台获取
var host = 'xxxxxxxxxx.mqtt.aliyuncs.com'; // 设置当前用户的接入点域名,接入点获取方法请参考接入准备章节文档,先在控制台创建实例
var port = 80; //WebSocket 协议服务端口,如果是走 HTTPS,设置443端口
var topic = 'Topic_xxxxxxxxxx'; //需要操作的 Topic,第一级父级 topic 需要在控制台申请
var useTLS = false; //是否走加密 HTTPS,如果走 HTTPS,设置为 true
var accessKey = 'xxxxxxxxxx'; //账号的 AccessKey,在阿里云控制台查看
var secretKey = 'xxxxxxxxxx'; //账号的的 SecretKey,在阿里云控制台查看
var cleansession = true;
var groupId = 'GID_xxxxxxxxxx'; //MQTT GroupID,创建实例后从 MQTT 控制台创建
var clientId = groupId '@@@00001'; //GroupId@@@DeviceId,由控制台创建的 Group ID 和自己指定的 Device ID 组合构成
var mqtt;
var reconnectTimeout = 2000;
var username = 'Signature|' accessKey '|' instanceId; //username和 Password 签名模式下的设置方法,参考文档 https://help.aliyun.com/document_detail/48271.html?spm=a2c4g.11186623.6.553.217831c3BSFry7
var password = "";
export default {
data() {
return {
mecont: []
}
},
onLoad() {
password = $crypto.HmacSHA1(clientId, secretKey).toString($crypto.enc.Base64);
MQTTconnect(this);
},
methods: {
}
}
function MQTTconnect(_this) {
mqtt = new $mqtt.Client(
host, //MQTT 域名
port, //WebSocket 端口,如果使用 HTTPS 加密则配置为443,否则配置80
clientId //客户端 ClientId
);
var options = {
userName: username,
password: password,
useSSL: useTLS, //如果使用 HTTPS 加密则配置为 true
onSuccess: function onConnect() { //连接成功
_this.mecont.push(new Date() ": " "连接成功");
// Connection succeeded; subscribe to our topic
//订阅消息
mqtt.subscribe(topic "/subDemo1", {
qos: 0
});
//测试消息推送
var message = new $mqtt.Message("APP测试消息推送!!"); //set body
message.destinationName = topic; // set topic
// //发送 P2P 消息,topic 设置方式参考https://help.aliyun.com/document_detail/96176.html?spm=a2c4g.11186623.6.586.694f7cb4oookL7
// message = new $mqtt.Message("Hello mqtt P2P Msg!!"); //set body
// message.destinationName = topic "/p2p/" clientId; // set topic
mqtt.send(message);
},
onFailure: function(message) { //连接失败
_this.mecont.push(new Date() ": " "连接失败" JSON.stringify(message));
//连接失败,重新连接
setTimeout(MQTTconnect, reconnectTimeout);
}
};
mqtt.onConnectionLost = function onConnectionLost(response) {
_this.mecont.push(new Date() ": " "连接中断" JSON.stringify(response));
//连接失败,重新连接
setTimeout(MQTTconnect, reconnectTimeout);
};
mqtt.onMessageArrived = function onMessageArrived(message) {
var topic = message.destinationName;
var payload = message.payloadString;
_this.mecont.push(new Date() ": " "收到新消息" topic " " payload);
};
mqtt.connect(options);
}
收起阅读 »

提供一个自定义键盘 可以在uniapp中使用 也可以在h5中使用 非常精简可扩展
主要code
<template>
<div class="page_comp">
<button type="button" @click="openKeyBoard('s10')">唤起键盘,有小数点</button>
<button type="button" @click="openKeyBoard('s20')">唤起键盘,无小数点</button>
<button type="button" @click="openKeyBoard('s30')">唤起键盘,替换键值</button>
<button type="button" @click="openKeyBoard('s40')">唤起键盘,替换确认</button>
<button type="button" @click="openKeyBoard('s50')">无确认键</button>
<div style="position: fixed;z-index: 1999;font-size: .3rem;color: #000;background-color: #fff;">
{{valList.join("")}}
</div>
<!-- start -->
<div class="md-popup bottom" v-show="ShowKeyBoard">
<div class="md-popup-mask" v-show="ShowKeyBoard"></div>
<!-- <transition name="cus-slide-up"> -->
<div class="cus-num-key-slot" @click="cloKeyBoard" v-if="keyS == 's50'">
收起键盘
</div>
<div class="cus-key-cont" v-show="ShowKeyBoard">
<div class="key-num">
<ul class="key-num-list">
<li @click="getKeyValue(item)" v-if="!(keyS == 's20'&&item == '.')" :class="['key-num-item',item === 0 && keyS == 's20'?'large-item':'']" v-for="(item,index) in keyList" :key="index"><span v-if="item == '.' && keyS == 's30'">{{keyReplce}}</span><span v-else>{{item}}</span></li>
<li @click="delKeyValue" v-if="keyS == 's50'" class="key-num-item no-bg delete"><span></span></li>
<li @click="cloKeyBoard" v-if="!(keyS == 's50')" class="key-num-item slidedown"><span></span></li>
</ul>
</div>
<div class="keyb-ope" v-if="!(keyS == 's50')">
<ul class="keyb-ope-list">
<li class="keyb-ope-item delete" @click="delKeyValue"><span></span></li>
<li class="keyb-ope-item confirm" @click="entKeyValue"><span>{{keyEntText}}</span></li>
</ul>
</div>
</div>
<!-- </transition> -->
</div>
<!-- end -->
</div>
</template>
<script>
export default {
name: 'keybord',
data () {
return {
keyList: [1,2,3,4,5,6,7,8,9,'.',0],
valList: [],
temList: [],
keyS: 's10',
keyReplce: 'x',
keyEntText: '确定',
ShowKeyBoard: false
}
},
methods: {
getKeyValue(item){
this.valList.push(item);
//console.log(this.valList);
},
delKeyValue(){
let del_in = this.valList.length-1;
this.valList.splice(del_in,1);
//console.log(this.valList);
},
cloKeyBoard(){
this.ShowKeyBoard = false;
},
entKeyValue(){
this.temList = this.valList;
let resNum = this.temList.join("");
console.log(resNum);
},
openKeyBoard(value){
if(!value || value == 's10'){
this.ShowKeyBoard = true;
}
if(value == 's20'){
this.keyS = value;
this.ShowKeyBoard = true;
}
if(value == 's30'){
this.keyS = value;
this.ShowKeyBoard = true;
}
if(value == 's40'){
this.keyEntText = '支付';
this.ShowKeyBoard = true;
}
if(value == 's50'){
this.keyS = value;
this.ShowKeyBoard = true;
}
}
},
watch: {
ShowKeyBoard: function(){
if(this.ShowKeyBoard){
}else{
this.keyEntText = '确定';
this.keyS = 's10';
}
}
},
mounted: function(){
},
created: function(){
}
}
</script>
<style>
.md-popup {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: -webkit-box;
display: flex;
z-index: 1000;
}
.md-popup.bottom {
flex-direction: column;
justify-content: flex-end;
}
.md-popup-mask {
top: 0;
right: 0;
bottom: 0;
left: 0;
position: absolute;
pointer-events: auto;
background-color: rgba(0,0,0,.6);
z-index: 1;
}
.cus-key-cont{position:relative;-webkit-user-select:none;-webkit-tap-highlight-color:transparent;display:-webkit-box;display:-webkit-flex;display:flex;width:100%;height:4.28rem;z-index:9}
.cus-key-cont:after{content:"";position:absolute;z-index:2;-webkit-transform-origin:100% 50%;transform-origin:100% 50%;-webkit-transform:scaleY(.5) translateY(-100%);transform:scaleY(.5) translateY(-100%);top:0;left:0;right:auto;bottom:auto;width:100%;border-top:0.02rem solid #e2e4ea;-webkit-transform-origin:50% 0;transform-origin:50% 0}
@media (-webkit-min-device-pixel-ratio:3),(min-resolution:3dppx){.cus-key-cont:after{-webkit-transform:scaleY(.33) translateY(-100%);transform:scaleY(.33) translateY(-100%)}
}.cus-key-cont .key-num,.cus-key-cont .keyb-ope{display:-webkit-box;display:-webkit-flex;display:flex}
.cus-key-cont .key-num{-webkit-box-flex:3;-webkit-flex:3;flex:3;background:#f9fafb}
.cus-key-cont .key-num .key-num-list{float:left;width:100%}
.cus-key-cont .key-num .key-num-list .key-num-item{position:relative;float:left;width:33.3%;height:1.07rem;padding-top:0.05rem;text-align:center;line-height:1.07rem;font-size:0.52rem;font-weight:500;font-family:Microsoft YaHei,微软雅黑,Arial,sans-serif;color:#111a34;-webkit-transition:background .3s;transition:background .3s;background:#fff;box-sizing:border-box;cursor: pointer;}
.cus-key-cont .key-num .key-num-list .key-num-item:before{content:"";position:absolute;z-index:2;-webkit-transform:scaleX(.5) translateX(100%);transform:scaleX(.5) translateX(100%);top:0;right:0;left:auto;bottom:auto;border-right:0.02rem solid #e2e4ea;height:100%;-webkit-transform-origin:100% 50%;transform-origin:100% 50%}
@media (-webkit-min-device-pixel-ratio:3),(min-resolution:3dppx){.cus-key-cont .key-num .key-num-list .key-num-item:before{-webkit-transform:scaleX(.33) translateX(100%);transform:scaleX(.33) translateX(100%)}
}.cus-key-cont .key-num .key-num-list .key-num-item:after{content:"";position:absolute;z-index:2;-webkit-transform-origin:100% 50%;transform-origin:100% 50%;-webkit-transform:scaleY(.5) translateY(-100%);transform:scaleY(.5) translateY(-100%);top:0;left:0;right:auto;bottom:auto;width:100%;border-top:0.02rem solid #e2e4ea;-webkit-transform-origin:50% 0;transform-origin:50% 0}
@media (-webkit-min-device-pixel-ratio:3),(min-resolution:3dppx){.cus-key-cont .key-num .key-num-list .key-num-item:after{-webkit-transform:scaleY(.33) translateY(-100%);transform:scaleY(.33) translateY(-100%)}
}.cus-key-cont .key-num .key-num-list .key-num-item.no-bg{background:0 0}
.cus-key-cont .key-num .key-num-list .key-num-item:nth-of-type(-n+3):after{display:none}
.cus-key-cont .key-num .key-num-list .key-num-item:nth-of-type(3n){width:33.4%}
.cus-key-cont .key-num .key-num-list .key-num-item.delete{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABECAMAAABJe8AqAAAAdVBMVEUAAABBSF5GTWBBSF5CSmJBSF1BSF1hYXVCSV1CSF5SXGtBSV1BSF5DSV9ESl5FTWRBSV5BSF5BSV1BSF5BSV1CSl5BSV5CSV5CSV5DSl9DS2JOTmNBSF1CSV9CSl5ETGBJSWRCSV5CSV1ES19CSF1CSl5BSF2IZB1/AAAAJnRSTlMA1yffH5T1BfudCuvLWUQW8OTUtamjj4FzNy0QwIxNQBxoZkvCZK9RzSgAAAGQSURBVFjDzNW5jsJQDIXhQ8LNwpKwDfswA4Xf/xEpXLhwbo4AWcJVlEj/V6Q4yN9ePr8J8reUWOBcxQKXUmKBrcQCB4kFbqK3xNtXjAHFSvt7xACzjfavdRCw0/66Rwxw1H5zQgzw1yjwQAzwP9d+ixigXmh/MQsCWu3Pp4gBHtpvOsQAp0qBI2KAfq39HWKA+qr9zYs/uB4F/EauikzoJ2HoppNuDPAbecv1RdJQv5Sq44Bt5CHfV8H1xQQH+I3cZvq9fk9DfZFfAthGlhfYDaUSf+kB28jqDDCB9B3gN5ILvG+A30gukL4D3EZSgfQd4DeSC/bIAb+RXGB9A2wj77CjQmt9AmQ2kgrWJ0B+I7mQwIH8RnIh4SuAZ3VmbgMACMNAL0IF7L8iokposaLYEyDx5OyD3CKBQ6avqcBDKx8VMezW57DrH9fAJIHTj0wa+gKxhQxeCtERGN/hVyW+5wJiWqGAHSXQtMZmgpqqhIegpjonE9RVqZVLQWDWac0gqLlavgQ11/u1HxRBUH6BA3XHDDIvn0o0AAAAAElFTkSuQmCC) 50% no-repeat;background-size:0.46rem}
.cus-key-cont .key-num .key-num-list .key-num-item.slidedown{background:#fff url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGwAAABeAgMAAAC7uhn4AAAACVBMVEUAAAASHDYRGjQxUFCHAAAAAnRSTlMAgJsrThgAAAB/SURBVEjH7dUxDoAgEETRsbGgtvI0XkdP4xEoaOSUJgQzJMMmlpvAtL94YRuQ7flqEf2F2WazWsjtotvm6WbOWvgO5rx5utlsP5uzP84ehtlaX3xDt9R2oLOrpAe97aUlEySnIDkFySlITkFyCpJTkJyCyT4pOQXJ6U7Y29DuBThrzOxbC3kTAAAAAElFTkSuQmCC) 50% no-repeat;background-size:0.54rem}
.cus-key-cont .key-num .key-num-list .key-num-item.large-item{width:66.6%}
.cus-key-cont .key-num .key-num-list .key-num-item.active,.cus-key-cont .key-num .key-num-list .key-num-item:active{background-color:#f9fafb}
.cus-key-cont .key-num .key-num-list .key-num-item:after,.cus-key-cont .key-num .key-num-list .key-num-item:before{pointer-events:none}
.cus-key-cont .keyb-ope{-webkit-box-flex:1;-webkit-flex:1;flex:1}
.cus-key-cont .keyb-ope .keyb-ope-list{position:relative;float:left;width:100%;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column}
.cus-key-cont .keyb-ope .keyb-ope-list .keyb-ope-item{position:relative;float:left;width:100%;background:#fff;-webkit-transition:background .3s;transition:background .3s;cursor: pointer;}
.cus-key-cont .keyb-ope .keyb-ope-list .keyb-ope-item.delete{height:1.07rem;background:#fff url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABECAMAAABJe8AqAAAAdVBMVEUAAABBSF5GTWBBSF5CSmJBSF1BSF1hYXVCSV1CSF5SXGtBSV1BSF5DSV9ESl5FTWRBSV5BSF5BSV1BSF5BSV1CSl5BSV5CSV5CSV5DSl9DS2JOTmNBSF1CSV9CSl5ETGBJSWRCSV5CSV1ES19CSF1CSl5BSF2IZB1/AAAAJnRSTlMA1yffH5T1BfudCuvLWUQW8OTUtamjj4FzNy0QwIxNQBxoZkvCZK9RzSgAAAGQSURBVFjDzNW5jsJQDIXhQ8LNwpKwDfswA4Xf/xEpXLhwbo4AWcJVlEj/V6Q4yN9ePr8J8reUWOBcxQKXUmKBrcQCB4kFbqK3xNtXjAHFSvt7xACzjfavdRCw0/66Rwxw1H5zQgzw1yjwQAzwP9d+ixigXmh/MQsCWu3Pp4gBHtpvOsQAp0qBI2KAfq39HWKA+qr9zYs/uB4F/EauikzoJ2HoppNuDPAbecv1RdJQv5Sq44Bt5CHfV8H1xQQH+I3cZvq9fk9DfZFfAthGlhfYDaUSf+kB28jqDDCB9B3gN5ILvG+A30gukL4D3EZSgfQd4DeSC/bIAb+RXGB9A2wj77CjQmt9AmQ2kgrWJ0B+I7mQwIH8RnIh4SuAZ3VmbgMACMNAL0IF7L8iokposaLYEyDx5OyD3CKBQ6avqcBDKx8VMezW57DrH9fAJIHTj0wa+gKxhQxeCtERGN/hVyW+5wJiWqGAHSXQtMZmgpqqhIegpjonE9RVqZVLQWDWac0gqLlavgQ11/u1HxRBUH6BA3XHDDIvn0o0AAAAAElFTkSuQmCC) 50% no-repeat;background-size:0.42rem;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-flex:1;-webkit-flex:1;flex:1}
.cus-key-cont .keyb-ope .keyb-ope-list .keyb-ope-item.delete:active{background-color:#f9fafb}
.cus-key-cont .keyb-ope .keyb-ope-list .keyb-ope-item.confirm{padding-top:0.05rem;color:#fff;font-size:0.36rem;background:#2f86f6;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-flex:1;-webkit-flex:1;flex:1;-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;}
.cus-key-cont .keyb-ope .keyb-ope-list .keyb-ope-item.confirm:active{background-color:#2a78dc}
.cus-key-cont.simple .key-num-item{color:number-keyb-key-color-simple!important}
.cus-slide-up-enter,.cus-slide-up-leave-to {
-webkit-transform: translate3d(0,100%,0);
transform: translate3d(0,100%,0)
}
.cus-slide-up-enter-active {
-webkit-transition: -webkit-transform .3s cubic-bezier(.165,.84,.44,1);
transition: -webkit-transform .3s cubic-bezier(.165,.84,.44,1);
transition: transform .3s cubic-bezier(.165,.84,.44,1);
transition: transform .3s cubic-bezier(.165,.84,.44,1), -webkit-transform .3s cubic-bezier(.165,.84,.44,1)
}
.cus-slide-up-leave-active {
-webkit-transition: -webkit-transform .25s cubic-bezier(.165,.84,.44,1);
transition: -webkit-transform .25s cubic-bezier(.165,.84,.44,1);
transition: transform .25s cubic-bezier(.165,.84,.44,1);
transition: transform .25s cubic-bezier(.165,.84,.44,1), -webkit-transform .25s cubic-bezier(.165,.84,.44,1)
}
.cus-num-key-slot{
position: relative;
width: 100%;
height: 40px;
line-height: 40px;
background-color: #f8f8f8;
color: #666;
font-size: 14px;
z-index: 9;
text-align: center;
}
</style>
主要code
<template>
<div class="page_comp">
<button type="button" @click="openKeyBoard('s10')">唤起键盘,有小数点</button>
<button type="button" @click="openKeyBoard('s20')">唤起键盘,无小数点</button>
<button type="button" @click="openKeyBoard('s30')">唤起键盘,替换键值</button>
<button type="button" @click="openKeyBoard('s40')">唤起键盘,替换确认</button>
<button type="button" @click="openKeyBoard('s50')">无确认键</button>
<div style="position: fixed;z-index: 1999;font-size: .3rem;color: #000;background-color: #fff;">
{{valList.join("")}}
</div>
<!-- start -->
<div class="md-popup bottom" v-show="ShowKeyBoard">
<div class="md-popup-mask" v-show="ShowKeyBoard"></div>
<!-- <transition name="cus-slide-up"> -->
<div class="cus-num-key-slot" @click="cloKeyBoard" v-if="keyS == 's50'">
收起键盘
</div>
<div class="cus-key-cont" v-show="ShowKeyBoard">
<div class="key-num">
<ul class="key-num-list">
<li @click="getKeyValue(item)" v-if="!(keyS == 's20'&&item == '.')" :class="['key-num-item',item === 0 && keyS == 's20'?'large-item':'']" v-for="(item,index) in keyList" :key="index"><span v-if="item == '.' && keyS == 's30'">{{keyReplce}}</span><span v-else>{{item}}</span></li>
<li @click="delKeyValue" v-if="keyS == 's50'" class="key-num-item no-bg delete"><span></span></li>
<li @click="cloKeyBoard" v-if="!(keyS == 's50')" class="key-num-item slidedown"><span></span></li>
</ul>
</div>
<div class="keyb-ope" v-if="!(keyS == 's50')">
<ul class="keyb-ope-list">
<li class="keyb-ope-item delete" @click="delKeyValue"><span></span></li>
<li class="keyb-ope-item confirm" @click="entKeyValue"><span>{{keyEntText}}</span></li>
</ul>
</div>
</div>
<!-- </transition> -->
</div>
<!-- end -->
</div>
</template>
<script>
export default {
name: 'keybord',
data () {
return {
keyList: [1,2,3,4,5,6,7,8,9,'.',0],
valList: [],
temList: [],
keyS: 's10',
keyReplce: 'x',
keyEntText: '确定',
ShowKeyBoard: false
}
},
methods: {
getKeyValue(item){
this.valList.push(item);
//console.log(this.valList);
},
delKeyValue(){
let del_in = this.valList.length-1;
this.valList.splice(del_in,1);
//console.log(this.valList);
},
cloKeyBoard(){
this.ShowKeyBoard = false;
},
entKeyValue(){
this.temList = this.valList;
let resNum = this.temList.join("");
console.log(resNum);
},
openKeyBoard(value){
if(!value || value == 's10'){
this.ShowKeyBoard = true;
}
if(value == 's20'){
this.keyS = value;
this.ShowKeyBoard = true;
}
if(value == 's30'){
this.keyS = value;
this.ShowKeyBoard = true;
}
if(value == 's40'){
this.keyEntText = '支付';
this.ShowKeyBoard = true;
}
if(value == 's50'){
this.keyS = value;
this.ShowKeyBoard = true;
}
}
},
watch: {
ShowKeyBoard: function(){
if(this.ShowKeyBoard){
}else{
this.keyEntText = '确定';
this.keyS = 's10';
}
}
},
mounted: function(){
},
created: function(){
}
}
</script>
<style>
.md-popup {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: -webkit-box;
display: flex;
z-index: 1000;
}
.md-popup.bottom {
flex-direction: column;
justify-content: flex-end;
}
.md-popup-mask {
top: 0;
right: 0;
bottom: 0;
left: 0;
position: absolute;
pointer-events: auto;
background-color: rgba(0,0,0,.6);
z-index: 1;
}
.cus-key-cont{position:relative;-webkit-user-select:none;-webkit-tap-highlight-color:transparent;display:-webkit-box;display:-webkit-flex;display:flex;width:100%;height:4.28rem;z-index:9}
.cus-key-cont:after{content:"";position:absolute;z-index:2;-webkit-transform-origin:100% 50%;transform-origin:100% 50%;-webkit-transform:scaleY(.5) translateY(-100%);transform:scaleY(.5) translateY(-100%);top:0;left:0;right:auto;bottom:auto;width:100%;border-top:0.02rem solid #e2e4ea;-webkit-transform-origin:50% 0;transform-origin:50% 0}
@media (-webkit-min-device-pixel-ratio:3),(min-resolution:3dppx){.cus-key-cont:after{-webkit-transform:scaleY(.33) translateY(-100%);transform:scaleY(.33) translateY(-100%)}
}.cus-key-cont .key-num,.cus-key-cont .keyb-ope{display:-webkit-box;display:-webkit-flex;display:flex}
.cus-key-cont .key-num{-webkit-box-flex:3;-webkit-flex:3;flex:3;background:#f9fafb}
.cus-key-cont .key-num .key-num-list{float:left;width:100%}
.cus-key-cont .key-num .key-num-list .key-num-item{position:relative;float:left;width:33.3%;height:1.07rem;padding-top:0.05rem;text-align:center;line-height:1.07rem;font-size:0.52rem;font-weight:500;font-family:Microsoft YaHei,微软雅黑,Arial,sans-serif;color:#111a34;-webkit-transition:background .3s;transition:background .3s;background:#fff;box-sizing:border-box;cursor: pointer;}
.cus-key-cont .key-num .key-num-list .key-num-item:before{content:"";position:absolute;z-index:2;-webkit-transform:scaleX(.5) translateX(100%);transform:scaleX(.5) translateX(100%);top:0;right:0;left:auto;bottom:auto;border-right:0.02rem solid #e2e4ea;height:100%;-webkit-transform-origin:100% 50%;transform-origin:100% 50%}
@media (-webkit-min-device-pixel-ratio:3),(min-resolution:3dppx){.cus-key-cont .key-num .key-num-list .key-num-item:before{-webkit-transform:scaleX(.33) translateX(100%);transform:scaleX(.33) translateX(100%)}
}.cus-key-cont .key-num .key-num-list .key-num-item:after{content:"";position:absolute;z-index:2;-webkit-transform-origin:100% 50%;transform-origin:100% 50%;-webkit-transform:scaleY(.5) translateY(-100%);transform:scaleY(.5) translateY(-100%);top:0;left:0;right:auto;bottom:auto;width:100%;border-top:0.02rem solid #e2e4ea;-webkit-transform-origin:50% 0;transform-origin:50% 0}
@media (-webkit-min-device-pixel-ratio:3),(min-resolution:3dppx){.cus-key-cont .key-num .key-num-list .key-num-item:after{-webkit-transform:scaleY(.33) translateY(-100%);transform:scaleY(.33) translateY(-100%)}
}.cus-key-cont .key-num .key-num-list .key-num-item.no-bg{background:0 0}
.cus-key-cont .key-num .key-num-list .key-num-item:nth-of-type(-n+3):after{display:none}
.cus-key-cont .key-num .key-num-list .key-num-item:nth-of-type(3n){width:33.4%}
.cus-key-cont .key-num .key-num-list .key-num-item.delete{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABECAMAAABJe8AqAAAAdVBMVEUAAABBSF5GTWBBSF5CSmJBSF1BSF1hYXVCSV1CSF5SXGtBSV1BSF5DSV9ESl5FTWRBSV5BSF5BSV1BSF5BSV1CSl5BSV5CSV5CSV5DSl9DS2JOTmNBSF1CSV9CSl5ETGBJSWRCSV5CSV1ES19CSF1CSl5BSF2IZB1/AAAAJnRSTlMA1yffH5T1BfudCuvLWUQW8OTUtamjj4FzNy0QwIxNQBxoZkvCZK9RzSgAAAGQSURBVFjDzNW5jsJQDIXhQ8LNwpKwDfswA4Xf/xEpXLhwbo4AWcJVlEj/V6Q4yN9ePr8J8reUWOBcxQKXUmKBrcQCB4kFbqK3xNtXjAHFSvt7xACzjfavdRCw0/66Rwxw1H5zQgzw1yjwQAzwP9d+ixigXmh/MQsCWu3Pp4gBHtpvOsQAp0qBI2KAfq39HWKA+qr9zYs/uB4F/EauikzoJ2HoppNuDPAbecv1RdJQv5Sq44Bt5CHfV8H1xQQH+I3cZvq9fk9DfZFfAthGlhfYDaUSf+kB28jqDDCB9B3gN5ILvG+A30gukL4D3EZSgfQd4DeSC/bIAb+RXGB9A2wj77CjQmt9AmQ2kgrWJ0B+I7mQwIH8RnIh4SuAZ3VmbgMACMNAL0IF7L8iokposaLYEyDx5OyD3CKBQ6avqcBDKx8VMezW57DrH9fAJIHTj0wa+gKxhQxeCtERGN/hVyW+5wJiWqGAHSXQtMZmgpqqhIegpjonE9RVqZVLQWDWac0gqLlavgQ11/u1HxRBUH6BA3XHDDIvn0o0AAAAAElFTkSuQmCC) 50% no-repeat;background-size:0.46rem}
.cus-key-cont .key-num .key-num-list .key-num-item.slidedown{background:#fff url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGwAAABeAgMAAAC7uhn4AAAACVBMVEUAAAASHDYRGjQxUFCHAAAAAnRSTlMAgJsrThgAAAB/SURBVEjH7dUxDoAgEETRsbGgtvI0XkdP4xEoaOSUJgQzJMMmlpvAtL94YRuQ7flqEf2F2WazWsjtotvm6WbOWvgO5rx5utlsP5uzP84ehtlaX3xDt9R2oLOrpAe97aUlEySnIDkFySlITkFyCpJTkJyCyT4pOQXJ6U7Y29DuBThrzOxbC3kTAAAAAElFTkSuQmCC) 50% no-repeat;background-size:0.54rem}
.cus-key-cont .key-num .key-num-list .key-num-item.large-item{width:66.6%}
.cus-key-cont .key-num .key-num-list .key-num-item.active,.cus-key-cont .key-num .key-num-list .key-num-item:active{background-color:#f9fafb}
.cus-key-cont .key-num .key-num-list .key-num-item:after,.cus-key-cont .key-num .key-num-list .key-num-item:before{pointer-events:none}
.cus-key-cont .keyb-ope{-webkit-box-flex:1;-webkit-flex:1;flex:1}
.cus-key-cont .keyb-ope .keyb-ope-list{position:relative;float:left;width:100%;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column}
.cus-key-cont .keyb-ope .keyb-ope-list .keyb-ope-item{position:relative;float:left;width:100%;background:#fff;-webkit-transition:background .3s;transition:background .3s;cursor: pointer;}
.cus-key-cont .keyb-ope .keyb-ope-list .keyb-ope-item.delete{height:1.07rem;background:#fff url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABECAMAAABJe8AqAAAAdVBMVEUAAABBSF5GTWBBSF5CSmJBSF1BSF1hYXVCSV1CSF5SXGtBSV1BSF5DSV9ESl5FTWRBSV5BSF5BSV1BSF5BSV1CSl5BSV5CSV5CSV5DSl9DS2JOTmNBSF1CSV9CSl5ETGBJSWRCSV5CSV1ES19CSF1CSl5BSF2IZB1/AAAAJnRSTlMA1yffH5T1BfudCuvLWUQW8OTUtamjj4FzNy0QwIxNQBxoZkvCZK9RzSgAAAGQSURBVFjDzNW5jsJQDIXhQ8LNwpKwDfswA4Xf/xEpXLhwbo4AWcJVlEj/V6Q4yN9ePr8J8reUWOBcxQKXUmKBrcQCB4kFbqK3xNtXjAHFSvt7xACzjfavdRCw0/66Rwxw1H5zQgzw1yjwQAzwP9d+ixigXmh/MQsCWu3Pp4gBHtpvOsQAp0qBI2KAfq39HWKA+qr9zYs/uB4F/EauikzoJ2HoppNuDPAbecv1RdJQv5Sq44Bt5CHfV8H1xQQH+I3cZvq9fk9DfZFfAthGlhfYDaUSf+kB28jqDDCB9B3gN5ILvG+A30gukL4D3EZSgfQd4DeSC/bIAb+RXGB9A2wj77CjQmt9AmQ2kgrWJ0B+I7mQwIH8RnIh4SuAZ3VmbgMACMNAL0IF7L8iokposaLYEyDx5OyD3CKBQ6avqcBDKx8VMezW57DrH9fAJIHTj0wa+gKxhQxeCtERGN/hVyW+5wJiWqGAHSXQtMZmgpqqhIegpjonE9RVqZVLQWDWac0gqLlavgQ11/u1HxRBUH6BA3XHDDIvn0o0AAAAAElFTkSuQmCC) 50% no-repeat;background-size:0.42rem;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-flex:1;-webkit-flex:1;flex:1}
.cus-key-cont .keyb-ope .keyb-ope-list .keyb-ope-item.delete:active{background-color:#f9fafb}
.cus-key-cont .keyb-ope .keyb-ope-list .keyb-ope-item.confirm{padding-top:0.05rem;color:#fff;font-size:0.36rem;background:#2f86f6;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-flex:1;-webkit-flex:1;flex:1;-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;}
.cus-key-cont .keyb-ope .keyb-ope-list .keyb-ope-item.confirm:active{background-color:#2a78dc}
.cus-key-cont.simple .key-num-item{color:number-keyb-key-color-simple!important}
.cus-slide-up-enter,.cus-slide-up-leave-to {
-webkit-transform: translate3d(0,100%,0);
transform: translate3d(0,100%,0)
}
.cus-slide-up-enter-active {
-webkit-transition: -webkit-transform .3s cubic-bezier(.165,.84,.44,1);
transition: -webkit-transform .3s cubic-bezier(.165,.84,.44,1);
transition: transform .3s cubic-bezier(.165,.84,.44,1);
transition: transform .3s cubic-bezier(.165,.84,.44,1), -webkit-transform .3s cubic-bezier(.165,.84,.44,1)
}
.cus-slide-up-leave-active {
-webkit-transition: -webkit-transform .25s cubic-bezier(.165,.84,.44,1);
transition: -webkit-transform .25s cubic-bezier(.165,.84,.44,1);
transition: transform .25s cubic-bezier(.165,.84,.44,1);
transition: transform .25s cubic-bezier(.165,.84,.44,1), -webkit-transform .25s cubic-bezier(.165,.84,.44,1)
}
.cus-num-key-slot{
position: relative;
width: 100%;
height: 40px;
line-height: 40px;
background-color: #f8f8f8;
color: #666;
font-size: 14px;
z-index: 9;
text-align: center;
}
</style>
收起阅读 »

iOS 离线SDK集成示例
说明
本示例工程实现了从原生页面跳转 uniapp
页面,然后在 uniapp
页面中通过调用原生扩展 Module
插件的方法在跳转回原生页面,希望对那些想在现有原生工程中集成uni-app
的用户有所帮助;
运行方式
- 下载原生离线sdk,并解压;
- 将本帖子中的附件下载,并解压放到离线sdk的根目录中;
- 直接运行
HBuilder-Integrate.xcodeproj
即可;
效果
欢迎讨论
下载工程
说明
本示例工程实现了从原生页面跳转 uniapp
页面,然后在 uniapp
页面中通过调用原生扩展 Module
插件的方法在跳转回原生页面,希望对那些想在现有原生工程中集成uni-app
的用户有所帮助;
运行方式
- 下载原生离线sdk,并解压;
- 将本帖子中的附件下载,并解压放到离线sdk的根目录中;
- 直接运行
HBuilder-Integrate.xcodeproj
即可;
效果
欢迎讨论
下载工程
收起阅读 »
HBuilderx打包iOS教程
HBuilderx使用自有证书打包打包iOS需要两个iOS证书文件p12和.mobileprovision
如果还没这两个文件先申请!
HBuilder在线打包iOS步骤
1、打开HBuilder工具,选择完工的项目,点击发行,选择发行为原生安装包。
2、选择iOS打包,支持的设备类型(可以选择支持iPhone和支持ipad),选择使用苹果证书
AppID:跟申请证书描述.mobileprovision时选择的要一致(又称套装id,appid,BundleID,应用id,包名)
profile文件:选择上传配置文件.mobileprovision
私钥证书:上传.p12文件
私钥密码:输入创建p12设置的密码。
然后点击打包。
3、打包成功后,下载保存ipa,这个ipa包就能安装到手机测试了。
HBuilderx使用自有证书打包打包iOS需要两个iOS证书文件p12和.mobileprovision
如果还没这两个文件先申请!
HBuilder在线打包iOS步骤
1、打开HBuilder工具,选择完工的项目,点击发行,选择发行为原生安装包。
2、选择iOS打包,支持的设备类型(可以选择支持iPhone和支持ipad),选择使用苹果证书
AppID:跟申请证书描述.mobileprovision时选择的要一致(又称套装id,appid,BundleID,应用id,包名)
profile文件:选择上传配置文件.mobileprovision
私钥证书:上传.p12文件
私钥密码:输入创建p12设置的密码。
然后点击打包。
3、打包成功后,下载保存ipa,这个ipa包就能安装到手机测试了。