开发电商app的优势,力谱云助您开发电商app
随着电商企业的蓬勃发展,开发一款专属电商App成为了许多企业进军移动蓝海市场的不二选择。企业通过开发APP可以更有利的发展,那么开发电商App究竟有何优势呢?跟着力谱云,来了解一番吧!
> 用户体验更佳
优化用户体验,一直是企业在开发电商App中,最为看重的一个关键环节。通过AR、VR、AI等黑科技的融合运用,能为用户带来意想不到的惊喜体验, 提升用户粘性。力谱云APP开发平台,目前支持运用直播、大数据等科技技术为移动电商解决方案添砖加瓦。
随着电商企业的蓬勃发展,开发一款专属电商App成为了许多企业进军移动蓝海市场的不二选择。企业通过开发APP可以更有利的发展,那么开发电商App究竟有何优势呢?跟着力谱云,来了解一番吧!
> 用户体验更佳
优化用户体验,一直是企业在开发电商App中,最为看重的一个关键环节。通过AR、VR、AI等黑科技的融合运用,能为用户带来意想不到的惊喜体验, 提升用户粘性。力谱云APP开发平台,目前支持运用直播、大数据等科技技术为移动电商解决方案添砖加瓦。
收起阅读 »uni 文本框循环取值
//按钮方法
formSubmit: function(e, key) {
var keys = key * 3;//key是定位所在位置,比如遍历出来的第一行是0,第二行是1,我这边乘以3是因为我一行有3个文本框。
var inpArr = document.getElementsByTagName("input");//定位页面input ,所以这里如果页面有其他不是文本框的input 那要注意了。。。
const vip = inpArr[keys + 2].value;
const svip = inpArr[keys + 1].value;
const ssvip = inpArr[keys].value;
}
//页面代码
<view class="uni-card" v-for="(value, key) in list2" :key="key">
<view class="uni-flex uni-row am-margin-bottom-sm product-list-name">
<view style="flex: 1; line-height: 38upx;">{{ value.proName }} 【{{value.proSize}}】</view>
<view class="am-text-right" style="width: 140upx;">
<uni-badge text="待调价" type="danger"></uni-badge>
</view>
</view>
<view class="uni-flex uni-row product-list-right">
<view class="product-list-small">成本价</view>
<view class="product-list-small">SVIP价</view>
<view class="product-list-small">VIP价</view>
<view class="product-list-small">会员价</view>
</view>
<view class="uni-flex uni-row product-list-right">
<view class="product-list-money" style="border: 2upx solid #f1f1f1; font-size: 32upx; color: #FF5101; line-height: 70upx; font-weight: bold;">{{ value.proCbj }}</view>
<view class="product-list-money">
<input type="number" :value="value.proSSVip" name='ssvip1' />
</view>
<view class="product-list-money">
<input type="number" :value="value.proSVip" name='svip1' />
</view>
<view class="product-list-money">
<input type="number" :value="value.proVip" name='vip1' />
</view>
</view>
<view class="product-list-foot-font">
<text class="iconfont icon-yangshengqi" style="font-size: 20upx; color: #aaa; margin-right: 4upx;"></text>
<text style="color: #999; font-size: 26upx;">19-01-12</text>从<text>15.50</text>调为<text>{{ value.money }}</text>,差额<text>{{ value.rate }}</text>
</view>
<view class="am-text-center finance-list-btn">
<button type="warn" @tap="formSubmit(value.proID,key)">确认调价</button>
</view>
</view>
//按钮方法
formSubmit: function(e, key) {
var keys = key * 3;//key是定位所在位置,比如遍历出来的第一行是0,第二行是1,我这边乘以3是因为我一行有3个文本框。
var inpArr = document.getElementsByTagName("input");//定位页面input ,所以这里如果页面有其他不是文本框的input 那要注意了。。。
const vip = inpArr[keys + 2].value;
const svip = inpArr[keys + 1].value;
const ssvip = inpArr[keys].value;
}
//页面代码
<view class="uni-card" v-for="(value, key) in list2" :key="key">
<view class="uni-flex uni-row am-margin-bottom-sm product-list-name">
<view style="flex: 1; line-height: 38upx;">{{ value.proName }} 【{{value.proSize}}】</view>
<view class="am-text-right" style="width: 140upx;">
<uni-badge text="待调价" type="danger"></uni-badge>
</view>
</view>
<view class="uni-flex uni-row product-list-right">
<view class="product-list-small">成本价</view>
<view class="product-list-small">SVIP价</view>
<view class="product-list-small">VIP价</view>
<view class="product-list-small">会员价</view>
</view>
<view class="uni-flex uni-row product-list-right">
<view class="product-list-money" style="border: 2upx solid #f1f1f1; font-size: 32upx; color: #FF5101; line-height: 70upx; font-weight: bold;">{{ value.proCbj }}</view>
<view class="product-list-money">
<input type="number" :value="value.proSSVip" name='ssvip1' />
</view>
<view class="product-list-money">
<input type="number" :value="value.proSVip" name='svip1' />
</view>
<view class="product-list-money">
<input type="number" :value="value.proVip" name='vip1' />
</view>
</view>
<view class="product-list-foot-font">
<text class="iconfont icon-yangshengqi" style="font-size: 20upx; color: #aaa; margin-right: 4upx;"></text>
<text style="color: #999; font-size: 26upx;">19-01-12</text>从<text>15.50</text>调为<text>{{ value.money }}</text>,差额<text>{{ value.rate }}</text>
</view>
<view class="am-text-center finance-list-btn">
<button type="warn" @tap="formSubmit(value.proID,key)">确认调价</button>
</view>
</view>
UniPush开通指南
产品说明
Uni Push 是 DCloud 推出的推送产品,适用于uni-app、5+app、wap2app云端打包后的App应用。下面介绍一下如何申请开通及使用。
申请开通 Uni Push
Uni Push 需要在 开发者中心 申请开通后,方可使用。在开通此业务之前需要先根据页面提示完成邮箱验证,已验证邮箱请忽略。
Tips: 目前只有应用所有者可以操作 Uni Push。应用协作者暂不支持。
在通过实名认证以后,有两个入口可以进入 Uni Push 配置页面:
- 通过 HBuilderX 进入
- 通过开发者中心进入
通过 HBuilderX 进入
打开 HBuilderX,双击项目中的 “manifest.json” 文件,选择“App 模块配置”,向下找到“Push(消息推送)”,勾选后,点击 “uniPush” 下面的配置链接,即可进入 Uni Push 配置页面。如下图所示:
通过开发者中心进入
-
使用 HBuilder 账号登录 开发者中心 ,登录后会进入“我的应用”列表
<!-- ,如下图所示: -
在左侧菜单点击“uniPush”,然后选择 1.0或2.0,进入Uni Push 信息页,左上角显示为当前要操作的应用,点击可以切换应用。如下图所示:
开通 UniPush
用户首次使用 UniPush 功能时,需要向个推同步身份信息。已通过实名认证的用户,会直接将实名认证信息同步给个推。如下图所示:
未提交实名认证信息的用户,需要在页面中输入相关信息后提交,如下图所示:
应用开通 Uni Push 功能时,需要提交应用相关信息,如下图所示:
注意:在申请开通时,需要确保输入的 Android包名
或 iOS Bundle ID
必须与打包时配置的一致,否则可能会导致无法收到推送消息。
- Android平台:
Android包名必须与HBuilderX中App云端打包时配置的Android包名一致;Android 应用签名必须填入打包时使用证书的SHA1指纹。 - iOS平台
iOS BundleId必须与HBuilderX中App云端打包时配置的Bundle ID(AppID)一致。
如果已经开通 Uni Push,会看到如下页面:
<a id="ios"/>
iOS推送证书配置
iOS 平台还需要在 “配置管理”-“应用配置” 页面上传推送证书
如何获取推送证书请参考个推官方文档教程 iOS证书配置指南
云端打包
应用开通 Uni Push 功能以后,只需要在 HBuilderX 中打开manifest.json,选择“App SDK配置”,向下找到推送功能配置,勾选 “DCloud UniPush” 即可。
厂商推送参数设置(可选,应用离线时可提高推送成功率)
Uni Push 集成并统一了各个手机厂商的系统级推送,目前支持魅族、OPPO、华为、小米、VIVO。如果需要使用厂商推送,需要先在各厂商开发者平台申请。
申请通过后厂商会提供推送的相关参数,需要将这些参数配置到 DCloud 开发者中心后台。
厂商参数配置页面如下图所示:
修改应用信息
修改应用基本信息
在此页面可以修改应用名称、应用的 Android 包名和签名信息、iOS 包名。
关闭UniPush
当应用不再使用 UniPush 时,可在此页面关闭该功能。
重置 MasterSecret
MasterSecret 是 Uni Push 服务端API鉴权码,用于验证调用合法性。在调用服务端API时需要提供。如果 MasterSecret 泄漏,会对业务安全产生重大影响,可以在此处进行重置操作。重置 MasterSecret 会导致当前使用的 MasterSecret 失效,在进行重置操作前,请确认重置操作是否会对生产环境产生影响。如果确实需要进行重置,建议在业务低峰时段操作。
使用推送
推送使用方法,参考文档 UniPush使用指南 。
产品说明
Uni Push 是 DCloud 推出的推送产品,适用于uni-app、5+app、wap2app云端打包后的App应用。下面介绍一下如何申请开通及使用。
申请开通 Uni Push
Uni Push 需要在 开发者中心 申请开通后,方可使用。在开通此业务之前需要先根据页面提示完成邮箱验证,已验证邮箱请忽略。
Tips: 目前只有应用所有者可以操作 Uni Push。应用协作者暂不支持。
在通过实名认证以后,有两个入口可以进入 Uni Push 配置页面:
- 通过 HBuilderX 进入
- 通过开发者中心进入
通过 HBuilderX 进入
打开 HBuilderX,双击项目中的 “manifest.json” 文件,选择“App 模块配置”,向下找到“Push(消息推送)”,勾选后,点击 “uniPush” 下面的配置链接,即可进入 Uni Push 配置页面。如下图所示:
通过开发者中心进入
-
使用 HBuilder 账号登录 开发者中心 ,登录后会进入“我的应用”列表
-->
<!-- ,如下图所示: -
在左侧菜单点击“uniPush”,然后选择 1.0或2.0,进入Uni Push 信息页,左上角显示为当前要操作的应用,点击可以切换应用。如下图所示:
开通 UniPush
用户首次使用 UniPush 功能时,需要向个推同步身份信息。已通过实名认证的用户,会直接将实名认证信息同步给个推。如下图所示:
未提交实名认证信息的用户,需要在页面中输入相关信息后提交,如下图所示:
应用开通 Uni Push 功能时,需要提交应用相关信息,如下图所示:
注意:在申请开通时,需要确保输入的 Android包名
或 iOS Bundle ID
必须与打包时配置的一致,否则可能会导致无法收到推送消息。
- Android平台:
Android包名必须与HBuilderX中App云端打包时配置的Android包名一致;Android 应用签名必须填入打包时使用证书的SHA1指纹。 - iOS平台
iOS BundleId必须与HBuilderX中App云端打包时配置的Bundle ID(AppID)一致。
如果已经开通 Uni Push,会看到如下页面:
<a id="ios"/>
iOS推送证书配置
iOS 平台还需要在 “配置管理”-“应用配置” 页面上传推送证书
如何获取推送证书请参考个推官方文档教程 iOS证书配置指南
云端打包
应用开通 Uni Push 功能以后,只需要在 HBuilderX 中打开manifest.json,选择“App SDK配置”,向下找到推送功能配置,勾选 “DCloud UniPush” 即可。
厂商推送参数设置(可选,应用离线时可提高推送成功率)
Uni Push 集成并统一了各个手机厂商的系统级推送,目前支持魅族、OPPO、华为、小米、VIVO。如果需要使用厂商推送,需要先在各厂商开发者平台申请。
申请通过后厂商会提供推送的相关参数,需要将这些参数配置到 DCloud 开发者中心后台。
厂商参数配置页面如下图所示:
修改应用信息
修改应用基本信息
在此页面可以修改应用名称、应用的 Android 包名和签名信息、iOS 包名。
关闭UniPush
当应用不再使用 UniPush 时,可在此页面关闭该功能。
重置 MasterSecret
MasterSecret 是 Uni Push 服务端API鉴权码,用于验证调用合法性。在调用服务端API时需要提供。如果 MasterSecret 泄漏,会对业务安全产生重大影响,可以在此处进行重置操作。重置 MasterSecret 会导致当前使用的 MasterSecret 失效,在进行重置操作前,请确认重置操作是否会对生产环境产生影响。如果确实需要进行重置,建议在业务低峰时段操作。
使用推送
推送使用方法,参考文档 UniPush使用指南 。
收起阅读 »uni-app/mui/小程序 可用的 RSA/SHA/MD5 签名/加密 SDK
之前项目是web 项目, 用的 fucking-util-signature 可以满足需求.
最近准备使用uni-app 开发跨平台应用
但是发现 web-worker 里面不支持 crypto.getRandomValues, 所以搞了个兼容层使其可以完全跨平台使用.
github 地址: fucking-util-signature-all
之前项目是web 项目, 用的 fucking-util-signature 可以满足需求.
最近准备使用uni-app 开发跨平台应用
但是发现 web-worker 里面不支持 crypto.getRandomValues, 所以搞了个兼容层使其可以完全跨平台使用.
github 地址: fucking-util-signature-all
收起阅读 »自已写的一个原生底部选项卡的封装
现有的5 app中官方的原生底部tabbar选项卡例子简直反人类,分布在配置文件,util.js,index.html三个文件里面,而且还不会自动判断,稍微改点东西就出错,气到七窍生烟。一怒之下自己写了一个封装,用起来还不错,希望能帮到像我一样的人。
html中的使用方法:
var tabBarSet = {
activeIndex: 0,//载入时激活的选项
textSize: "12px",
fontSrc: "_www/fonts/mui.ttf",
color: "#ccc",
colorActive: "#f60",
items: [{
icon: "\ue262",
iconSize: "26px",
text: "首页",
click: function() {
mess.innerHTML = "点击了首页";
console.log("点击了首页");
}
},
{
icon: "\ue464",
iconSize: "26px",
text: "上传",
click: function() {
mess.innerHTML = "点击了上传";
console.log("点击了上传");
}
},
{
icon: "\ue502",
iconSize: "26px",
text: "设置",
click: function() {
var theurl = $.json("server") === null ? server : $.json("server");
mui.prompt("请输入服务器地址(需加https://)", theurl, "修改服务器ip地址", function(e) {
if (e.index === 1) {
$.json("server", e.value);
server = e.value;
mui.toast("服务器地址已修改为" e.value);
}
}, "div");
document.querySelector('.mui-popup-input input').value = theurl;
}
}
]
};
mui.plusReady(function() {
hh_tabbar(tabBarSet)
});
tabbar.js =>
(function() {
var xview = plus.nativeObj.View.getViewById("hhtabBar");
if (xview != null) {
xview.close();
}
var nview = null;
var nviewtags = [];
nview = new plus.nativeObj.View("hhtabBar");
window.hh_tabbarClear = function() {
nview.reset();
}
window.hh_tabbar = function(tabBarSet) {
var persent = 100 / (tabBarSet.items.length);
nview.setStyle({
left: "0px",
bottom: "0px",
width: "100%",
height: "60px"
});
nviewtags = [];
var currLeft = 0;
for (var i = 0; i < tabBarSet.items.length; i++) {
var tjson = tabBarSet.items[i];
nviewtags.push({
tag: "font",
id: "bar" + i,
text: tjson.icon,
position: {
top: "5px",
left: currLeft + "%",
width: persent + "%",
height: "50%"
},
textStyles: {
fontSrc: tabBarSet.fontSrc,
align: 'center',
color: tabBarSet.color,
size: tjson.iconSize
}
});
nviewtags.push({
tag: "font",
id: "barText" + i,
text: tjson.text,
position: {
top: "50%",
left: currLeft + "%",
width: persent + "%",
height: "50%"
},
textStyles: {
align: 'center',
color: tabBarSet.color,
size: tabBarSet.textSize
}
});
currLeft += persent;
}
//画最上面的那条线
nviewtags.push({
tag: 'rect',
id: 'BorderTop',
position: {
top: '0px',
left: '0px',
width: '100%',
height: '1px'
},
rectStyles: {
color: '#ccc'
}
});
nview.draw(nviewtags);
var myself = plus.webview.currentWebview();
myself.append(nview);
var pageW = window.innerWidth;
nview.addEventListener("click", function(e) {
var clientX = e.clientX;
var currIndex = 0;
var widthBlock = pageW / tabBarSet.items.length;
for (var i = 0; i < tabBarSet.items.length; i++) {
if (e.clientX > i * widthBlock && e.clientX < (i + 1) * widthBlock) {
currIndex = i;
tabbarUpdate(i, tabBarSet.colorActive);
} else {
tabbarUpdate(i, tabBarSet.color);
}
}
tabBarSet.items[currIndex].click.apply(nview, [e]);
});
for (var i = 0; i < tabBarSet.items.length; i++) {
if (tabBarSet.activeIndex === i) {
tabbarUpdate(i, tabBarSet.colorActive);
} else {
tabbarUpdate(i, tabBarSet.color);
}
}
};
var tabbarUpdate = function(TheIndex, TheColor) {
var thetag = nviewtags[TheIndex * 2];
thetag.textStyles.color = TheColor;
nview.drawText(thetag.text, thetag.position, thetag.textStyles, "bar" + TheIndex);
thetag = nviewtags[TheIndex * 2 + 1];
thetag.textStyles.color = TheColor;
nview.drawText(thetag.text, thetag.position, thetag.textStyles, "barText" + TheIndex);
}
})();
现有的5 app中官方的原生底部tabbar选项卡例子简直反人类,分布在配置文件,util.js,index.html三个文件里面,而且还不会自动判断,稍微改点东西就出错,气到七窍生烟。一怒之下自己写了一个封装,用起来还不错,希望能帮到像我一样的人。
html中的使用方法:
var tabBarSet = {
activeIndex: 0,//载入时激活的选项
textSize: "12px",
fontSrc: "_www/fonts/mui.ttf",
color: "#ccc",
colorActive: "#f60",
items: [{
icon: "\ue262",
iconSize: "26px",
text: "首页",
click: function() {
mess.innerHTML = "点击了首页";
console.log("点击了首页");
}
},
{
icon: "\ue464",
iconSize: "26px",
text: "上传",
click: function() {
mess.innerHTML = "点击了上传";
console.log("点击了上传");
}
},
{
icon: "\ue502",
iconSize: "26px",
text: "设置",
click: function() {
var theurl = $.json("server") === null ? server : $.json("server");
mui.prompt("请输入服务器地址(需加https://)", theurl, "修改服务器ip地址", function(e) {
if (e.index === 1) {
$.json("server", e.value);
server = e.value;
mui.toast("服务器地址已修改为" e.value);
}
}, "div");
document.querySelector('.mui-popup-input input').value = theurl;
}
}
]
};
mui.plusReady(function() {
hh_tabbar(tabBarSet)
});
tabbar.js =>
(function() {
var xview = plus.nativeObj.View.getViewById("hhtabBar");
if (xview != null) {
xview.close();
}
var nview = null;
var nviewtags = [];
nview = new plus.nativeObj.View("hhtabBar");
window.hh_tabbarClear = function() {
nview.reset();
}
window.hh_tabbar = function(tabBarSet) {
var persent = 100 / (tabBarSet.items.length);
nview.setStyle({
left: "0px",
bottom: "0px",
width: "100%",
height: "60px"
});
nviewtags = [];
var currLeft = 0;
for (var i = 0; i < tabBarSet.items.length; i++) {
var tjson = tabBarSet.items[i];
nviewtags.push({
tag: "font",
id: "bar" + i,
text: tjson.icon,
position: {
top: "5px",
left: currLeft + "%",
width: persent + "%",
height: "50%"
},
textStyles: {
fontSrc: tabBarSet.fontSrc,
align: 'center',
color: tabBarSet.color,
size: tjson.iconSize
}
});
nviewtags.push({
tag: "font",
id: "barText" + i,
text: tjson.text,
position: {
top: "50%",
left: currLeft + "%",
width: persent + "%",
height: "50%"
},
textStyles: {
align: 'center',
color: tabBarSet.color,
size: tabBarSet.textSize
}
});
currLeft += persent;
}
//画最上面的那条线
nviewtags.push({
tag: 'rect',
id: 'BorderTop',
position: {
top: '0px',
left: '0px',
width: '100%',
height: '1px'
},
rectStyles: {
color: '#ccc'
}
});
nview.draw(nviewtags);
var myself = plus.webview.currentWebview();
myself.append(nview);
var pageW = window.innerWidth;
nview.addEventListener("click", function(e) {
var clientX = e.clientX;
var currIndex = 0;
var widthBlock = pageW / tabBarSet.items.length;
for (var i = 0; i < tabBarSet.items.length; i++) {
if (e.clientX > i * widthBlock && e.clientX < (i + 1) * widthBlock) {
currIndex = i;
tabbarUpdate(i, tabBarSet.colorActive);
} else {
tabbarUpdate(i, tabBarSet.color);
}
}
tabBarSet.items[currIndex].click.apply(nview, [e]);
});
for (var i = 0; i < tabBarSet.items.length; i++) {
if (tabBarSet.activeIndex === i) {
tabbarUpdate(i, tabBarSet.colorActive);
} else {
tabbarUpdate(i, tabBarSet.color);
}
}
};
var tabbarUpdate = function(TheIndex, TheColor) {
var thetag = nviewtags[TheIndex * 2];
thetag.textStyles.color = TheColor;
nview.drawText(thetag.text, thetag.position, thetag.textStyles, "bar" + TheIndex);
thetag = nviewtags[TheIndex * 2 + 1];
thetag.textStyles.color = TheColor;
nview.drawText(thetag.text, thetag.position, thetag.textStyles, "barText" + TheIndex);
}
})();
收起阅读 »
uni-app/mui/小程序 可用的 RSA/SHA/MD5 签名/加密 SDK
之前项目是web 项目, 用的 fucking-util-signature 可以满足需求.
最近准备使用uni-app 开发跨平台应用
但是发现 web-worker 里面不支持 crypto.getRandomValues, 所以搞了个兼容层使其可以完全跨平台使用.
github 地址: fucking-util-signature-all
之前项目是web 项目, 用的 fucking-util-signature 可以满足需求.
最近准备使用uni-app 开发跨平台应用
但是发现 web-worker 里面不支持 crypto.getRandomValues, 所以搞了个兼容层使其可以完全跨平台使用.
github 地址: fucking-util-signature-all
收起阅读 »uni-app项目展示屏幕文字滚动效果
插件预览图
使用教程
1.插件代码拷贝
- 下载后把components目录下screenTextScroll.vue文件拷贝到自己项目目录下
2.插件全局配置
- 在项目里main.js中配置如下代码
import screenTextScroll from './components/screenTextScroll.vue'
Vue.component('textscroll',screenTextScroll)
3.插件使用
- vue页面使用
<template>
<view class="content">
<textscroll :list="list"/>
</view>
</template>
<script>
export default {
data() {
return {
list:['1分钟前,无夏购买了会员','2分钟前,无夏购买了会员','3分钟前,无夏购买了会员']
};
},
onLoad() {},
methods: {
}
};
</script>
<style>
</style>
兼容性
uni-app项目中使用都兼容
插件预览图
使用教程
1.插件代码拷贝
- 下载后把components目录下screenTextScroll.vue文件拷贝到自己项目目录下
2.插件全局配置
- 在项目里main.js中配置如下代码
import screenTextScroll from './components/screenTextScroll.vue'
Vue.component('textscroll',screenTextScroll)
3.插件使用
- vue页面使用
<template>
<view class="content">
<textscroll :list="list"/>
</view>
</template>
<script>
export default {
data() {
return {
list:['1分钟前,无夏购买了会员','2分钟前,无夏购买了会员','3分钟前,无夏购买了会员']
};
},
onLoad() {},
methods: {
}
};
</script>
<style>
</style>
兼容性
uni-app项目中使用都兼容
收起阅读 »【疑难杂症】HBuilder 打包后百度/高德原生地图不可用的解决办法
【问题描述】
使用 plus.maps 创建原生百度/高德地图,在真机调试的时候地图显示正常,打包(apk)后地图无法显示。
【问题截图】
【问题原因】
因为 HBuilder 已经不怎么维护,官网推荐使用 HBuilderX,并且推测这两个开发工具的云端打包不是使用的一套系统,
随着 HBuilder 的停止维护对应的云端打包系统也停止了维护,所以产生了此问题。
【解决方案】
下载最新版 HBuilderX 打开项目,直接提交云端打包即可。
【效果展示】
使用 plus.maps 相关接口创建的原生(百度)地图
【问题描述】
使用 plus.maps 创建原生百度/高德地图,在真机调试的时候地图显示正常,打包(apk)后地图无法显示。
【问题截图】
【问题原因】
因为 HBuilder 已经不怎么维护,官网推荐使用 HBuilderX,并且推测这两个开发工具的云端打包不是使用的一套系统,
随着 HBuilder 的停止维护对应的云端打包系统也停止了维护,所以产生了此问题。
【解决方案】
下载最新版 HBuilderX 打开项目,直接提交云端打包即可。
【效果展示】
使用 plus.maps 相关接口创建的原生(百度)地图
解决页面被输入框顶起不回弹的问题!
如果输入框在页面中比较低。 激活输入框后, 页面会被顶起, 并且不会自动回来。
如果关闭了页面拉动。 那顶起后用手滑都回不来。 很郁闷。
解决方案:
在输入框加入 @blur="blur_input"
<input type="number" name="pn" @blur="blur_input" v-model="phoneno" maxlength="11"></input>
方法:
blur_input:function() {
uni.pageScrollTo({
scrollTop:0,
})
},
更多uni.pageScrollTo的使用方法。请查看文档。
如果输入框在页面中比较低。 激活输入框后, 页面会被顶起, 并且不会自动回来。
如果关闭了页面拉动。 那顶起后用手滑都回不来。 很郁闷。
解决方案:
在输入框加入 @blur="blur_input"
<input type="number" name="pn" @blur="blur_input" v-model="phoneno" maxlength="11"></input>
方法:
blur_input:function() {
uni.pageScrollTo({
scrollTop:0,
})
},
更多uni.pageScrollTo的使用方法。请查看文档。
收起阅读 »去设置里打开相机权限
function openCamera(){
var msg = "请在应用权限里设置允许使用相机权限";
mui.alert(msg,"开启相机权限","去开启",function(){
if (mui.os.ios) {
plus.runtime.openURL("app-settings:CAMERA");
} else {
var main = plus.android.runtimeMainActivity();
var Intent = plus.android.importClass("android.content.Intent");
var Build = plus.android.importClass("android.os.Build");
var Uri = plus.android.importClass("android.net.Uri");
var intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT >= 9) {//系统8.0以上的
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.setData(Uri.fromParts("package", main.getPackageName(), null));
} else if (Build.VERSION.SDK_INT <= 8) {//系统8.0以下的
intent.setAction(Intent.ACTION_VIEW);
intent.setClassName("com.android.settings", "com.android.setting.InstalledAppDetails");
intent.putExtra("com.android.settings.ApplicationPkgName", main.getPackageName());
}
main.startActivity(intent);
//
}
})
};
function openCamera(){
var msg = "请在应用权限里设置允许使用相机权限";
mui.alert(msg,"开启相机权限","去开启",function(){
if (mui.os.ios) {
plus.runtime.openURL("app-settings:CAMERA");
} else {
var main = plus.android.runtimeMainActivity();
var Intent = plus.android.importClass("android.content.Intent");
var Build = plus.android.importClass("android.os.Build");
var Uri = plus.android.importClass("android.net.Uri");
var intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT >= 9) {//系统8.0以上的
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.setData(Uri.fromParts("package", main.getPackageName(), null));
} else if (Build.VERSION.SDK_INT <= 8) {//系统8.0以下的
intent.setAction(Intent.ACTION_VIEW);
intent.setClassName("com.android.settings", "com.android.setting.InstalledAppDetails");
intent.putExtra("com.android.settings.ApplicationPkgName", main.getPackageName());
}
main.startActivity(intent);
//
}
})
};
收起阅读 »
个推平台消息推送踩坑经验分享
以下为官方说明
使用个推平台推送消息,在ios平台和安卓平台的运行机制并不完全相同,
下面对安卓平台和IOS平台进行分别描述
个推支持安卓可以发送普通消息和透传消息方式,ios只支持透传消息这种方式推送。
(一)IOS平台
IOS平台在处理消息时会因为程序是否在线处理逻辑会有不同
1.应用在线:
应用在线时服务器推送的消息不会进入消息中心。
如果页面中监听了“receive”事件则会触发事件的回调。
如果消息是通过APS通道发送到终端,用户可以在“receive”事件回调的“PushMesage”对象
中获取“aps”属性的值。
2应用不在线:
如果当前应用不在线,服务器推送的消息会进入系统消息中心。当用户点击消息,
则会启动HTML5+应用,并且在监听了“click”事件的页面中触发事件的回调。
3.本地消息:
当开发者创建本地消息时,本地消息会进入消息中心。如果开发者监听了“receive”事件,
则会在监听页面触发receive事件回调。如需要区分收到的消息是否是本地消息,
用户需要在payload节点添加标识。
(二)Android平台:
对安卓平台发送的普通push消息和符合格式的透传消息都会进入系统的消息中心。
透传消息如不符合格式则会触发监听页面的“receive”事件不会显示在消息中心。
安卓平台发送的普通消息都会进入消息中心,用户可以点击触发消息。
1.发送普通消息:
服务器可以向安卓平台发送三种类型的普通消息“通知”“下载”“网址”,
发送“通知”消息会启动HTML5+应用,如果是“下载”消息则会调用系统的下载管理器
下载指定文件。点击“网址”消息则会调用系统浏览器打开指定的网址。
2.发送透传消息:
当设备收到服务器发送的透传消息时,不会触发页面监听的receive事件。
当用户点击消息中心消息时会触发监听页面的“click”事件。
如果用户点击多个消息时,会多次触发“click”事件。
不符指定合格式的透传消息不会进入系统的消息中心,
会在监听“receive”事件的页面触发事件回调。
- 踩坑总结如下:
- 1.实际测试发现大部分安卓机只会在应用在后台或者在线时才会收到消息,点击消息会只会触发newintent的事件,而click和receive事件不会触发(暂无发现什么情况下会触发);
- 2.而苹果机离线或者后台应用时收到消息时,点击通知栏消息只触发newintent事件,当应用在前台时,只触发receive事件;(ios暂无发现什么情况会触发click事件)
- 3.经测试发现eval("(" + str + ")")转json这个方法在ios并不会执行,安卓机正常执行;
- 4.由于要兼容安卓的透传消息的格式,所以导致payload不是标准,所以ios接收的payload并不是标准的json字符串,要做特殊处理
- 5.parseJSON(str)的str只接收标准的json字符串,不然会报错。
- 6.如果obj本来就是一个JSON对象,那么使用eval()函数转换后(哪怕是多次转换)还是JSON对象,但是使用parseJSON()函数处理后会有问题(抛出语法异常)。参考:https://www.cnblogs.com/guoziyi/p/6003752.html
*/
一、以下是watcher.js实现逻辑
if(window.plus) {
newsClick();
} else {
document.addEventListener('plusready', newsClick, false);
}
function newsClick() {
//获取个推 CID
//mui.toast(plus.push.getClientInfo().clientid);
// 监听plusready事件
//仅支持竖屏显示
plus.screen.lockOrientation("portrait-primary");
plus.push.addEventListener("click", function(msg) {//为了兼容处理,暂时未发现可触发的情况
msg = (plus.os.name == 'iOS') ? msg : eval('(' + msg + ')');
if(plus.os.name=='iOS') {//ios当前应用离线时
if(msg.aps){
pushGetRun(msg.payload);
}
}else{//安卓用户点击消息中心的消息会触发监听页面的“click”事件
if(msg.payload){
var payload = eval('(' + msg.payload + ')');
pushGetRun(payload);
}
}
}, false);
plus.push.addEventListener("receive", function(msg) {
//获取透传数据,统一将回调对象msg处理成json对象
msg = (plus.os.name == 'iOS') ? msg : eval('(' + msg + ')');
if(plus.os.name == 'iOS'){//IOS应用在线时会触发“receive”事件的回调
if(msg.payload){
if(typeof(msg.payload) == "string"){
// mui.alert("payload(String): " + msg.payload);
//字符串处理
var payloadJson = toJSON(toJSONStr2(toJSONStr1(msg.payload))); //这个是透传消息的内容,格式为`{title:"通知标题",content:"通知内容",payload:'{"url":"_www/view/discovery/discoverydetail.html","params":{"article_id":51}}'}`
if(payloadJson.payload){
newsConfirm(payloadJson.payload);//弹出新消息层
}
}else if(typeof(msg.payload) == "object"){
if(msg.payload.payload){
var payloadObj = null;
if(typeof(msg.payload.payload) == 'string'){
payloadObj = toJSON(toJSONStr2(toJSONStr1(msg.payload.payload)));//转为object
}else if(typeof(msg.payload.payload) == "object"){
payloadObj = msg.payload.payload;
}
if(payloadObj){
newsConfirm(payloadObj);//弹出新消息层
}else{//异常处理
// clicked("_www/view/index.html", {"subpage_id":"_www/view/home/home.html"});//默认打开首页
}
}
}
}
}else {//安卓不符指定合格式的透传消息不会进入系统的消息中心,会在监听“receive”事件的页面触发事件回调
if(msg.payload){
newsConfirm(msg.payload);//弹出新消息层
}else{//异常处理
}
//创建本地消息
// plus.push.createMessage(msg.content, msg.payload, {
// title: msg.title,
// cover: false
// });
}
}, false);
function pushGetRun(payload) {//用参数打开指定页面
//eval()函数将字符串转换时需要区分是否是ios
var data = (plus.os.name == 'iOS') ? payload : eval('(' + payload + ')');
if(data.url&&data.hasOwnProperty("params")){
clicked(data.url, data.params);
}else{//异常处理
mui.toast("参数缺失或错误");
clicked("_www/view/index.html", {"subpage_id":"_www/view/home/home.html"});//默认打开首页
}
}
//程序从后台被第三方程序调用并传入新意图事件,通过测试发现,安卓只调用该事件,ios应用离线或者后台时只会调用此事件,ios应用处于前台会调用receive的监听事件
document.addEventListener("newintent", openWebviewFromOthers, false);
//获取通知栏(app未启动)点击、第三方程序启动本app
function openWebviewFromOthers() {
var args = plus.runtime.arguments;
if(args.indexOf('wechat') < 0 && args) {
// mui.toast("----args----" +JSON.stringify(args));
pushGetRun(args);
}
}
function newsConfirm(payload){
plus.nativeUI.confirm("收到一条新消息,是否立即查看", function(e) {
if(e.index == 0) {
pushGetRun(payload);
}
}, "新消息通知", ["查看", "忽略"]);
}
};
/*
* 针对ios不能执行eval("(" + str ")")来强制转化成json对象,
* 所以要自定义函数来将不标准的字符串转化成标准的字符串,在利用JSON.parse()方法来转化成json对象;
* 以下为调用例子:
* var a = `{title:"通知标题",content:"通知内容",payload:'{"url":"_www/view/discovery/discoverydetail.html","params":{"article_id":51}}'}`;
* toJSON(toJSONStr2(toJSONStr1(a)));//测试
*/
function toJSONStr1(str){
//全局将字符串 '{ 和 }' 替换成 { 和 } ,主要是为了统一"个推推送消息的透传内容的格式(而安卓需要传字符串而导致不是payload不是json对象)
return str.replace(/'{/g,"{").replace(/}'/g, "}");
}
function toJSONStr2(str) { //全局将属性名添加上双引号 ""
return str.replace(/([\$\w]+)\s*:/g, function(_, $1){return '"'+$1+'":'});
}
function toJSON(str) { //处理标准格式的字符串成json对象
return JSON.parse(str);
}
二、在view目录新建一个watcher.html,引入watcher.js即可;
三、在app入口文件 index.html做以下声明,用于应用启动时全局监听:
//消息事件监听
var watcherObj = plus.webview.getWebviewById("_www/view/watcher.html");
if(!watcherObj){//不存在才创建
var watcher = plus.webview.create("_www/view/watcher.html", "_www/view/watcher.html");
//创建完隐藏
watcher.hide();
}
四、个推平台上的使用:
由于个推对于推送通知(普通消息)的功能目前仅支持安卓用户,所以为了统一和兼容,所以要使用“透传消息”来进行推送;
”透传内容“------”消息内容“的参考例子:
{
title: "通知标题",
content: "通知内容",
payload: '{"url":"_www/view/discovery/discoverydetail.html","params":{"article_id":51}}'
}
IOS参数设置----payload的自定义值参考如下:
{
"url": "_www/view/discovery/discoverydetail.html",
"params": {
"article_id": 51
}
}
五、特别注意:经过测试,魅族机器 Notification 的奇葩问题,就是其的消息内容(对应上面”透传内容“--”消息内容“的content的值)不能带有中文字符的!和英文字符的!(参考:http://blog.csdn.net/u013045971/article/details/70173532);但是消息标题可以带;如果非要使用感叹号的话,可以使用特殊字符的感叹号﹗(来源:http://xh.5156edu.com/page/18466.html)
六、以下附件是个推平台上要注意的事项截图;
以上全部,欢迎大家一起讨论!
以下为官方说明
使用个推平台推送消息,在ios平台和安卓平台的运行机制并不完全相同,
下面对安卓平台和IOS平台进行分别描述
个推支持安卓可以发送普通消息和透传消息方式,ios只支持透传消息这种方式推送。
(一)IOS平台
IOS平台在处理消息时会因为程序是否在线处理逻辑会有不同
1.应用在线:
应用在线时服务器推送的消息不会进入消息中心。
如果页面中监听了“receive”事件则会触发事件的回调。
如果消息是通过APS通道发送到终端,用户可以在“receive”事件回调的“PushMesage”对象
中获取“aps”属性的值。
2应用不在线:
如果当前应用不在线,服务器推送的消息会进入系统消息中心。当用户点击消息,
则会启动HTML5+应用,并且在监听了“click”事件的页面中触发事件的回调。
3.本地消息:
当开发者创建本地消息时,本地消息会进入消息中心。如果开发者监听了“receive”事件,
则会在监听页面触发receive事件回调。如需要区分收到的消息是否是本地消息,
用户需要在payload节点添加标识。
(二)Android平台:
对安卓平台发送的普通push消息和符合格式的透传消息都会进入系统的消息中心。
透传消息如不符合格式则会触发监听页面的“receive”事件不会显示在消息中心。
安卓平台发送的普通消息都会进入消息中心,用户可以点击触发消息。
1.发送普通消息:
服务器可以向安卓平台发送三种类型的普通消息“通知”“下载”“网址”,
发送“通知”消息会启动HTML5+应用,如果是“下载”消息则会调用系统的下载管理器
下载指定文件。点击“网址”消息则会调用系统浏览器打开指定的网址。
2.发送透传消息:
当设备收到服务器发送的透传消息时,不会触发页面监听的receive事件。
当用户点击消息中心消息时会触发监听页面的“click”事件。
如果用户点击多个消息时,会多次触发“click”事件。
不符指定合格式的透传消息不会进入系统的消息中心,
会在监听“receive”事件的页面触发事件回调。
- 踩坑总结如下:
- 1.实际测试发现大部分安卓机只会在应用在后台或者在线时才会收到消息,点击消息会只会触发newintent的事件,而click和receive事件不会触发(暂无发现什么情况下会触发);
- 2.而苹果机离线或者后台应用时收到消息时,点击通知栏消息只触发newintent事件,当应用在前台时,只触发receive事件;(ios暂无发现什么情况会触发click事件)
- 3.经测试发现eval("(" + str + ")")转json这个方法在ios并不会执行,安卓机正常执行;
- 4.由于要兼容安卓的透传消息的格式,所以导致payload不是标准,所以ios接收的payload并不是标准的json字符串,要做特殊处理
- 5.parseJSON(str)的str只接收标准的json字符串,不然会报错。
- 6.如果obj本来就是一个JSON对象,那么使用eval()函数转换后(哪怕是多次转换)还是JSON对象,但是使用parseJSON()函数处理后会有问题(抛出语法异常)。参考:https://www.cnblogs.com/guoziyi/p/6003752.html
*/
一、以下是watcher.js实现逻辑
if(window.plus) {
newsClick();
} else {
document.addEventListener('plusready', newsClick, false);
}
function newsClick() {
//获取个推 CID
//mui.toast(plus.push.getClientInfo().clientid);
// 监听plusready事件
//仅支持竖屏显示
plus.screen.lockOrientation("portrait-primary");
plus.push.addEventListener("click", function(msg) {//为了兼容处理,暂时未发现可触发的情况
msg = (plus.os.name == 'iOS') ? msg : eval('(' + msg + ')');
if(plus.os.name=='iOS') {//ios当前应用离线时
if(msg.aps){
pushGetRun(msg.payload);
}
}else{//安卓用户点击消息中心的消息会触发监听页面的“click”事件
if(msg.payload){
var payload = eval('(' + msg.payload + ')');
pushGetRun(payload);
}
}
}, false);
plus.push.addEventListener("receive", function(msg) {
//获取透传数据,统一将回调对象msg处理成json对象
msg = (plus.os.name == 'iOS') ? msg : eval('(' + msg + ')');
if(plus.os.name == 'iOS'){//IOS应用在线时会触发“receive”事件的回调
if(msg.payload){
if(typeof(msg.payload) == "string"){
// mui.alert("payload(String): " + msg.payload);
//字符串处理
var payloadJson = toJSON(toJSONStr2(toJSONStr1(msg.payload))); //这个是透传消息的内容,格式为`{title:"通知标题",content:"通知内容",payload:'{"url":"_www/view/discovery/discoverydetail.html","params":{"article_id":51}}'}`
if(payloadJson.payload){
newsConfirm(payloadJson.payload);//弹出新消息层
}
}else if(typeof(msg.payload) == "object"){
if(msg.payload.payload){
var payloadObj = null;
if(typeof(msg.payload.payload) == 'string'){
payloadObj = toJSON(toJSONStr2(toJSONStr1(msg.payload.payload)));//转为object
}else if(typeof(msg.payload.payload) == "object"){
payloadObj = msg.payload.payload;
}
if(payloadObj){
newsConfirm(payloadObj);//弹出新消息层
}else{//异常处理
// clicked("_www/view/index.html", {"subpage_id":"_www/view/home/home.html"});//默认打开首页
}
}
}
}
}else {//安卓不符指定合格式的透传消息不会进入系统的消息中心,会在监听“receive”事件的页面触发事件回调
if(msg.payload){
newsConfirm(msg.payload);//弹出新消息层
}else{//异常处理
}
//创建本地消息
// plus.push.createMessage(msg.content, msg.payload, {
// title: msg.title,
// cover: false
// });
}
}, false);
function pushGetRun(payload) {//用参数打开指定页面
//eval()函数将字符串转换时需要区分是否是ios
var data = (plus.os.name == 'iOS') ? payload : eval('(' + payload + ')');
if(data.url&&data.hasOwnProperty("params")){
clicked(data.url, data.params);
}else{//异常处理
mui.toast("参数缺失或错误");
clicked("_www/view/index.html", {"subpage_id":"_www/view/home/home.html"});//默认打开首页
}
}
//程序从后台被第三方程序调用并传入新意图事件,通过测试发现,安卓只调用该事件,ios应用离线或者后台时只会调用此事件,ios应用处于前台会调用receive的监听事件
document.addEventListener("newintent", openWebviewFromOthers, false);
//获取通知栏(app未启动)点击、第三方程序启动本app
function openWebviewFromOthers() {
var args = plus.runtime.arguments;
if(args.indexOf('wechat') < 0 && args) {
// mui.toast("----args----" +JSON.stringify(args));
pushGetRun(args);
}
}
function newsConfirm(payload){
plus.nativeUI.confirm("收到一条新消息,是否立即查看", function(e) {
if(e.index == 0) {
pushGetRun(payload);
}
}, "新消息通知", ["查看", "忽略"]);
}
};
/*
* 针对ios不能执行eval("(" + str ")")来强制转化成json对象,
* 所以要自定义函数来将不标准的字符串转化成标准的字符串,在利用JSON.parse()方法来转化成json对象;
* 以下为调用例子:
* var a = `{title:"通知标题",content:"通知内容",payload:'{"url":"_www/view/discovery/discoverydetail.html","params":{"article_id":51}}'}`;
* toJSON(toJSONStr2(toJSONStr1(a)));//测试
*/
function toJSONStr1(str){
//全局将字符串 '{ 和 }' 替换成 { 和 } ,主要是为了统一"个推推送消息的透传内容的格式(而安卓需要传字符串而导致不是payload不是json对象)
return str.replace(/'{/g,"{").replace(/}'/g, "}");
}
function toJSONStr2(str) { //全局将属性名添加上双引号 ""
return str.replace(/([\$\w]+)\s*:/g, function(_, $1){return '"'+$1+'":'});
}
function toJSON(str) { //处理标准格式的字符串成json对象
return JSON.parse(str);
}
二、在view目录新建一个watcher.html,引入watcher.js即可;
三、在app入口文件 index.html做以下声明,用于应用启动时全局监听:
//消息事件监听
var watcherObj = plus.webview.getWebviewById("_www/view/watcher.html");
if(!watcherObj){//不存在才创建
var watcher = plus.webview.create("_www/view/watcher.html", "_www/view/watcher.html");
//创建完隐藏
watcher.hide();
}
四、个推平台上的使用:
由于个推对于推送通知(普通消息)的功能目前仅支持安卓用户,所以为了统一和兼容,所以要使用“透传消息”来进行推送;
”透传内容“------”消息内容“的参考例子:
{
title: "通知标题",
content: "通知内容",
payload: '{"url":"_www/view/discovery/discoverydetail.html","params":{"article_id":51}}'
}
IOS参数设置----payload的自定义值参考如下:
{
"url": "_www/view/discovery/discoverydetail.html",
"params": {
"article_id": 51
}
}
五、特别注意:经过测试,魅族机器 Notification 的奇葩问题,就是其的消息内容(对应上面”透传内容“--”消息内容“的content的值)不能带有中文字符的!和英文字符的!(参考:http://blog.csdn.net/u013045971/article/details/70173532);但是消息标题可以带;如果非要使用感叹号的话,可以使用特殊字符的感叹号﹗(来源:http://xh.5156edu.com/page/18466.html)
六、以下附件是个推平台上要注意的事项截图;
以上全部,欢迎大家一起讨论!
收起阅读 »希望uni-app打包成app的时候能够把webview内核打包进去
在一些手机上经常会遇到,因为手机自带webview内核过低,导致页面上的一些问题,希望uni-app能自己打包上,调用自己的。
在一些手机上经常会遇到,因为手机自带webview内核过低,导致页面上的一些问题,希望uni-app能自己打包上,调用自己的。